-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move CLI to its own module; improve test coverage
- Loading branch information
Showing
6 changed files
with
148 additions
and
73 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
"""Command-line interface functionality for the Drover interface""" | ||
import argparse | ||
import logging | ||
import sys | ||
from pathlib import Path | ||
|
||
import yaml | ||
from pydantic import ValidationError | ||
|
||
from drover import __version__, Drover, SettingsError, UpdateError | ||
from drover.models import Settings | ||
|
||
_logger = logging.getLogger(__name__) | ||
|
||
|
||
def _parse_arguments(): | ||
parser = argparse.ArgumentParser(description=__doc__.partition('\n')[0]) | ||
parser.add_argument('--version', '-V', action='version', version=f'%(prog)s {__version__}') | ||
group = parser.add_mutually_exclusive_group() | ||
group.add_argument('--verbose', '-v', action='count', default=0, help='increase output verbosity') | ||
group.add_argument('--quiet', action='store_true', help='disable output') | ||
group = parser.add_mutually_exclusive_group() | ||
group.add_argument('--interactive', action='store_true', help='enable interactive output (i.e. for a PTY)') | ||
group.add_argument('--non-interactive', action='store_true', help='disable interactive output') | ||
|
||
parser.add_argument('--settings-file', default=Path('drover.yml'), type=Path, | ||
help='Settings file name (default: "drover.yml")') | ||
parser.add_argument('--install-path', default=Path(), type=Path, | ||
help='Package install path (e.g. from "pip install -t"; default: working directory)') | ||
parser.add_argument('stage', type=str) | ||
return parser.parse_args() | ||
|
||
|
||
def _parse_settings(settings_file_name: Path) -> Settings: | ||
try: | ||
with open(settings_file_name, 'r') as settings_file: | ||
return Settings.parse_obj(yaml.safe_load(settings_file)) | ||
except (ValueError, ValidationError) as e: | ||
_logger.error('Settings file is invalid: %s', e) | ||
_logger.debug('', exc_info=e) | ||
sys.exit(1) | ||
except FileNotFoundError as e: | ||
_logger.error('Settings file does not exist: %s', e) | ||
_logger.debug('', exc_info=e) | ||
sys.exit(1) | ||
|
||
|
||
def main(): | ||
"""The main command-line entry point for the Drover interface""" | ||
arguments = _parse_arguments() | ||
|
||
if not arguments.quiet: | ||
logging.basicConfig(format='%(message)s', stream=sys.stdout) | ||
logging_level = max(1, logging.INFO - (10 * arguments.verbose)) | ||
_logger.setLevel(logging_level) | ||
|
||
interactive = True if arguments.interactive else False if arguments.non_interactive else sys.__stdin__.isatty() | ||
|
||
settings_file_name = arguments.settings_file | ||
install_path: Path = arguments.install_path | ||
|
||
settings: Settings = _parse_settings(settings_file_name) | ||
|
||
try: | ||
drover = Drover(settings, arguments.stage, interactive=interactive) | ||
drover.update(install_path) | ||
except SettingsError as e: | ||
_logger.error('Initialization failed: %s', e) | ||
_logger.debug('', exc_info=e) | ||
sys.exit(1) | ||
except UpdateError as e: | ||
_logger.error('Update failed: %s', e) | ||
_logger.debug('', exc_info=e) | ||
sys.exit(1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# pylint: disable=protected-access | ||
from dataclasses import dataclass | ||
from pathlib import Path | ||
from unittest import TestCase | ||
from unittest.mock import patch | ||
|
||
import drover | ||
import drover.cli | ||
|
||
from tests.test_drover import get_basic_settings | ||
|
||
|
||
@dataclass | ||
class MockArguments: | ||
stage: str | ||
quiet: bool | ||
interactive: bool = True | ||
non_interactive: bool = False | ||
settings_file: Path = Path('drover.yml') | ||
install_path: Path = Path('.') | ||
|
||
|
||
class TestDroverCLI(TestCase): | ||
def test_basic_run(self): | ||
expected_stage_name = 'stage' | ||
expected_settings = get_basic_settings(expected_stage_name) | ||
expected_interactive = True | ||
mock_arguments = MockArguments( | ||
stage='stage', | ||
quiet=True, | ||
interactive=expected_interactive, non_interactive=not expected_interactive) | ||
with patch.object(drover.cli, '_parse_arguments', return_value=mock_arguments) as mock_parse_arguments, \ | ||
patch.object(drover.cli, '_parse_settings', return_value=expected_settings) as mock_parse_settings, \ | ||
patch.object(drover.cli, 'Drover', autospec=drover.Drover) as mock_drover: | ||
drover.cli.main() | ||
mock_drover.assert_called_with(expected_settings, expected_stage_name, interactive=expected_interactive) | ||
mock_parse_arguments.assert_called() | ||
mock_parse_settings.assert_called_with(mock_arguments.settings_file) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters