Source code for shellbot.machines

# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import importlib
import logging

from .base import Machine, State, Transition
from .input import Input
from .sequence import Sequence
from .steps import Steps
from .menu import Menu

__all__ = [
    'Input',
    'Machine',
    'Sequence',
    'Steps',
    'Menu',
]

[docs]class MachineFactory(object): """ Provides new state machines In simple situations, you can rely on standard machines, and provide any parameters by these. For example:: factory = MachineFactory(module='shellbot.machines.input' question="What's Up, Doc?") ... machine = factory.get_machine() When you provide different state machines for direct channels and for group channels, overlay member functions as in this example:: class GreatMachineForDirectChannel(Machine): ... class MachineOnlyForGroup(Machine): ... class MyFactory(MachineFactory): def get_machine_for_direct_channel(self, bot): return GreatMachineForDirectChannel( ... ) def get_machine_for_group_channel(self, bot): return MachineOnlyForGroup( ... ) """ def __init__(self, module=None, name=None, **kwargs): """ Provides new state machines :param module: The python module to import :type module: str :param name: The class name to instantiate (optional) :type name: str If no name is provided, than we use the last part of the module instead. Other parameters are given to the instantiated object. Example:: factory = MachineFactory('shellbot.machines.input') machine = factory.get_machine() # Input() Example:: factory = MachineFactory('shellbot.machines.base', 'Machine') machine = factory.get_machine() # Machine() """ self.module = module self.name = name self.parameters = kwargs if kwargs else {}
[docs] def get_machine(self, bot=None): """ Gets a new state machine :param bot: The bot associated with this state machine :type bot: ShellBot Example:: my_machine = factory.get_machine(bot=my_bot) my_machine.start() This function detects the kind of channel that is associated with this bot, and provides a suitable state machine. """ if bot and bot.channel and bot.channel.is_direct: return self.get_machine_for_direct_channel(bot) elif bot and bot.channel and bot.channel.is_group: return self.get_machine_for_group_channel(bot) else: return self.get_default_machine(bot)
[docs] def get_machine_for_direct_channel(self, bot): """ Gets a new state machine for a direct channel :param bot: The bot associated with this state machine :type bot: ShellBot Example:: my_machine = factory.get_machine_for_direct_channel(bot=my_bot) my_machine.start() This function can be overlaid in a subclass for adapting the production of state machines for direct channels. """ return self.get_machine_from_class(bot=bot, module=self.module, name=self.name, **self.parameters)
[docs] def get_machine_for_group_channel(self, bot): """ Gets a new state machine for a group channel :param bot: The bot associated with this state machine :type bot: ShellBot Example:: my_machine = factory.get_machine_for_group_channel(bot=my_bot) my_machine.start() This function can be overlaid in a subclass for adapting the production of state machines for group channels. """ return self.get_machine_from_class(bot=bot, module=self.module, name=self.name, **self.parameters)
[docs] def get_default_machine(self, bot): """ Gets a new state machine :param bot: The bot associated with this state machine :type bot: ShellBot Example:: my_machine = factory.get_default_machine(bot=my_bot) my_machine.start() This function can be overlaid in a subclass for adapting the production of state machines for default case. """ return self.get_machine_from_class(bot=bot, module=self.module, name=self.name, **self.parameters)
[docs] def get_machine_from_class(self, bot, module, name, **kwargs): """ Gets a new state machine from a module :param bot: The bot associated with this state machine :type bot: ShellBot :param module: The python module to import :type module: str :param name: The class name to instantiate (optional) :type name: str Example:: machine = factory.get_machine_from_class(my_bot, 'shellbot.machines.base', 'Machine') """ assert self.module # need python module name try: handle = importlib.import_module(self.module) logging.debug(u"Loading machine '{}'".format(self.module)) except ImportError: logging.error(u"Unable to import '{}'".format(self.module)) return None if not self.name: self.name = self.module.rsplit('.', 1)[1].capitalize() cls = getattr(handle, self.name) return cls(bot, **kwargs)