Source code for almanac.commands.command_base

from __future__ import annotations

import inspect
import itertools

from abc import ABC, abstractmethod
from typing import Iterable, List, Optional, Tuple, Union

from ..constants import CommandLineDefaults
from ..types import CommandCoroutine


[docs]class CommandBase(ABC): """The abstract base class for command types. This ABC is extended into two variants: * :class:`~almanac.commands.frozen_command.FrozenCommand` * :class:`~almanac.commands.mutable_command.MutableCommand` It is unlikely that you should need to manually instantiate instances of these classes, as they are mainly used internally for the command-generating decorators accessible via :class:`~almanac.core.application.Application`. """ def __init__( self, coroutine: CommandCoroutine, *, name: Optional[str] = None, description: Optional[str] = None, aliases: Optional[Union[str, Iterable[str]]] = None ) -> None: self._name = name if name is not None else coroutine.__name__ if description is not None: self._description = description elif (maybe_doc := coroutine.__doc__) is not None: self._description = maybe_doc else: self._description = CommandLineDefaults.DOC self._aliases: List[str] = [] if isinstance(aliases, str): self._aliases.append(aliases) elif aliases is not None: self._aliases.extend(aliases) self._impl_signature = inspect.signature(coroutine) self._impl_coroutine = coroutine self._has_var_kw_arg = any( p.kind == p.VAR_KEYWORD for _, p in self._impl_signature.parameters.items() ) self._has_var_pos_arg = any( p.kind == p.VAR_POSITIONAL for _, p in self._impl_signature.parameters.items() ) @property def has_var_kw_arg( self ) -> bool: """Whether this command has a ``**kwargs`` argument.""" return self._has_var_kw_arg @property def has_var_pos_arg( self ) -> bool: """Whether this command has a ``*args`` argument.""" return self._has_var_kw_arg @property def name( self ) -> str: """The primary name of this function.""" return self._name @name.setter def name( self, new_name: str ) -> None: self._abstract_name_setter(new_name) @abstractmethod def _abstract_name_setter( self, new_name: str ) -> None: """Abstract name setter to allow for access control.""" @property def description( self ) -> str: """A description for this command.""" return self._description @description.setter def description( self, new_description: str ) -> None: self._abstract_description_setter(new_description) @abstractmethod def _abstract_description_setter( self, new_description: str ) -> None: """Abstract description setter to allow for access control.""" @property def aliases( self ) -> Tuple[str, ...]: """Aliases for this command.""" return tuple(self._aliases)
[docs] @abstractmethod def add_alias( self, *aliases: str ) -> None: """Abstract alias appender to allow for access control."""
@property def identifiers( self ) -> Tuple[str, ...]: """A combination of this command's name and any of its aliases.""" return tuple(itertools.chain( (self._name,), self._aliases )) @property def signature( self ) -> inspect.Signature: """The signature of the user-written coroutine wrapped by this command.""" return self._impl_signature @property def coroutine( self ) -> CommandCoroutine: """The internal coroutine that this command wraps.""" return self._impl_coroutine