diff --git a/bonobo/commands/run.py b/bonobo/commands/run.py index 6de6bf6..fb93e77 100644 --- a/bonobo/commands/run.py +++ b/bonobo/commands/run.py @@ -26,6 +26,20 @@ def get_default_services(filename, services=None): return services or {} +def _install_requirements(requirements): + """Install requirements given a path to requirements.txt file.""" + import importlib + import pip + + pip.main(['install', '-r', requirements]) + # Some shenanigans to be sure everything is importable after this, especially .egg-link files which + # are referenced in *.pth files and apparently loaded by site.py at some magic bootstrap moment of the + # python interpreter. + pip.utils.pkg_resources = importlib.reload(pip.utils.pkg_resources) + import site + importlib.reload(site) + + def execute(filename, module, install=False, quiet=False, verbose=False): import runpy from bonobo import Graph, run, settings @@ -39,16 +53,8 @@ def execute(filename, module, install=False, quiet=False, verbose=False): if filename: if os.path.isdir(filename): if install: - import importlib - import pip requirements = os.path.join(filename, 'requirements.txt') - pip.main(['install', '-r', requirements]) - # Some shenanigans to be sure everything is importable after this, especially .egg-link files which - # are referenced in *.pth files and apparently loaded by site.py at some magic bootstrap moment of the - # python interpreter. - pip.utils.pkg_resources = importlib.reload(pip.utils.pkg_resources) - import site - importlib.reload(site) + _install_requirements(requirements) pathname = filename for filename in DEFAULT_GRAPH_FILENAMES: @@ -58,7 +64,8 @@ def execute(filename, module, install=False, quiet=False, verbose=False): if not os.path.exists(filename): raise IOError('Could not find entrypoint (candidates: {}).'.format(', '.join(DEFAULT_GRAPH_FILENAMES))) elif install: - raise RuntimeError('Cannot --install on a file (only available for dirs containing requirements.txt).') + requirements = os.path.join(os.path.dirname(filename), 'requirements.txt') + _install_requirements(requirements) context = runpy.run_path(filename, run_name='__bonobo__') elif module: context = runpy.run_module(module, run_name='__bonobo__') diff --git a/tests/test_commands.py b/tests/test_commands.py index 280308d..e2d7b7b 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -1,3 +1,4 @@ +import os import runpy import sys from unittest.mock import patch @@ -70,6 +71,24 @@ def test_run_path(runner, capsys): assert out[2].startswith('Baz ') +@all_runners +def test_install_requirements_for_dir(runner): + dirname = get_examples_path('types') + with patch('bonobo.commands.run._install_requirements') as install_mock: + runner('run', '--install', dirname) + install_mock.assert_called_once_with( + os.path.join(dirname, 'requirements.txt')) + + +@all_runners +def test_install_requirements_for_file(runner): + dirname = get_examples_path('types') + with patch('bonobo.commands.run._install_requirements') as install_mock: + runner('run', '--install', os.path.join(dirname, 'strings.py')) + install_mock.assert_called_once_with( + os.path.join(dirname, 'requirements.txt')) + + @all_runners def test_version(runner, capsys): runner('version')