-
-
Save tamaramalysh5991/db7dee5d0abdc655919247dcf8d3b2cc to your computer and use it in GitHub Desktop.
Command Pattern (Abstract handlers to execute commands)
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
import re | |
from abc import abstractmethod | |
from ..registry import register_handler | |
__all__ = ( | |
'AbstractCommandHandler', | |
'CommandPayload', | |
'AbstractRegexpCommandHandler' | |
) | |
class CommandPayload(object): | |
"""Simple Data Transfer Object for encapsulate command's data | |
Is simply an object with attributes corresponding to the names of | |
the data you want to pass around or return | |
Example: | |
>>> cmd = CommandPayload(yumber_name="some info", target="some info") | |
>>> cmd.yumber_name | |
>>> "some info" | |
""" | |
def __init__(self, **kwargs): | |
"""Define attributes form kwargs""" | |
self.__dict__.update(kwargs) | |
class CommandHandlerMetaClass(type): | |
"""Register command handler classes in a registry""" | |
def __new__(cls, clsname, bases, attrs): | |
handler_class = super(CommandHandlerMetaClass, cls).\ | |
__new__(cls, clsname, bases, attrs) | |
if not clsname.startswith('Abstract'): | |
register_handler(handler_class) | |
return handler_class | |
class AbstractCommandHandler(object, metaclass=CommandHandlerMetaClass): | |
"""Abstract class for representation command handler | |
Each handler can process command in message and send answer if | |
message matches the condition of current handler | |
""" | |
def __init__( | |
self, | |
phone: str, | |
msg: str, | |
media_files=None, | |
): | |
"""Define constructor | |
Args: | |
phone (str): user phone from sms | |
msg (str): body of sms -> the command to | |
be executed if it matches the pattern | |
media_files: list of media urls from MMS | |
""" | |
self.phone = phone | |
self.msg = msg or '' | |
self.media_files = media_files or [] | |
@abstractmethod | |
def check_condition(self, *args, **kwargs): | |
"""Check the message match command's condition""" | |
@abstractmethod | |
def prefetch_required_data(self) -> CommandPayload: | |
"""Get data needed to process command from message or cache and | |
encapsulate data to `Command` object | |
""" | |
@abstractmethod | |
def execute_command(self, command: CommandPayload = None, *args, **kwargs): | |
"""Execute command from message | |
Main method for handler where command should be processed. | |
The main method of Handler remains abstract, so that each | |
specific Handler will define it in its own way. | |
""" | |
@classmethod | |
def handler_name(cls): | |
"""Get handler name to identify handler in string mode""" | |
return cls.__name__ | |
def __call__(self, do_check: bool = True, *args, **kwargs): | |
"""Override __call_ method for execute handler | |
If Handler correspond its requirements, | |
the command processing is started. | |
Args: | |
do_check: The flag determines whether to perform a conditions check | |
Used in cases where we directly call the handler and we don't | |
need to additionally check its conditions | |
""" | |
if not do_check or self.check_condition(): | |
return self.execute_command(command=self.prefetch_required_data()) | |
class AbstractRegexpCommandHandler(AbstractCommandHandler): | |
"""Abstract class of simple regexp command handler | |
The handler process plain commands the conditions of which can be | |
described by regexp pattern | |
Attributes: | |
* pattern (str): regex pattern to which the command should correspond | |
""" | |
pattern = None | |
def check_condition(self): | |
"""Check the message match command's pattern""" | |
return re.search(self.pattern, self.msg, re.IGNORECASE) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment