Crystalnix/termius-cli

View on GitHub
termius/core/commands/single.py

Summary

Maintainability
A
0 mins
Test Coverage
# -*- coding: utf-8 -*-
"""Module with base commands per entries."""
from collections import namedtuple
from ..exceptions import ArgumentRequiredException
from ..storage.strategies import (
    RelatedSaveStrategy,
    RelatedGetStrategy,
)
from .mixins import GetRelationMixin, GetObjectsMixin, InstanceOperationMixin
from .base import AbstractCommand


class RequiredOptions(namedtuple('RequiredOptions',
                                 ['create', 'update', 'delete'])):
    """Class for keeping required options."""

    @staticmethod
    def __new__(cls, create=(), update=('entry',), delete=('entry',)):
        """Make field optionals."""
        return super(RequiredOptions, cls).__new__(cls, create, update, delete)


class DetailCommand(GetRelationMixin, GetObjectsMixin,
                    InstanceOperationMixin, AbstractCommand):
    """Command for operating with models by id or names."""

    save_strategy = RelatedSaveStrategy
    get_strategy = RelatedGetStrategy

    required_options = RequiredOptions()

    def create(self, parsed_args):
        """Handle create new instance command."""
        self.validate_args(parsed_args, 'create')
        self.create_instance(parsed_args)

    def update(self, parsed_args):
        """Handle update command.

        Get models from storage, parse args and update models.
        """
        self.validate_args(parsed_args, 'update')
        instances = self.get_objects(parsed_args.entry)
        for i in instances:
            self.update_instance(parsed_args, i)

    def delete(self, parsed_args):
        """Handle delete command.

        Get models from storage, delete models.
        """
        self.validate_args(parsed_args, 'delete')
        instances = self.get_objects(parsed_args.entry)
        for i in instances:
            self.delete_instance(i)

    def get_parser(self, prog_name):
        """Add more arguments to parser."""
        parser = super(DetailCommand, self).get_parser(prog_name)
        parser.add_argument(
            '-d', '--delete',
            action='store_true', help='delete entries'
        )
        parser.add_argument(
            '-L', '--label', metavar='NAME',
            help="name or rename the entry label NAME"
        )
        parser.add_argument(
            'entry', nargs='*', metavar='ID or NAME',
            help='select the entry with ID or NAME'
        )
        return parser

    def take_action(self, parsed_args):
        """Process CLI call."""
        if parsed_args.delete:
            self.delete(parsed_args)
        elif not parsed_args.entry:
            self.create(parsed_args)
        else:
            self.update(parsed_args)

    def validate_args(self, args, action):
        """Raise ArgumentRequiredException if any required options' missed."""
        arg_list = getattr(self.required_options, action)
        missed_options_list = [
            i for i in arg_list if getattr(args, i) is None
        ]
        if missed_options_list:
            message = self.generate_requirement_message(missed_options_list)
            raise ArgumentRequiredException(message)

    # pylint: disable=no-self-use
    def generate_requirement_message(self, options):
        """Render error message for missed required options."""
        if len(options) == 1:
            return 'Option {} is required!'.format(options[0])
        return 'Options {} are required!'.format(','.join(options))