def test_to_yaml_no_defaults_empty(self):
        storage_config = StorageConfiguration()

        data = {}
        storage_config.to_yaml(data, defaults=False)

        self.assertEquals({'entities': {}, 'stores': {}}, data)
    def test_to_yaml_defaults(self):
        storage_config = StorageConfiguration()

        data = {}
        storage_config.to_yaml(data, defaults=True)

        self.assertDefaultEntities(data['entities'])
        self.assertDefaultFileStoreConfig(data['stores'])
 def test_add_default_stores_all_off(self):
     store_configs = {}
     StorageConfiguration.add_default_stores_as_yaml(store_configs,
                                                     file=False,
                                                     sqlite=False,
                                                     mongo=False,
                                                     redis=False,
                                                     logger=False)
     self.assertEquals({}, store_configs)
Exemple #4
0
 def __init__(self, name):
     BaseContainerConfigurationData.__init__(self, name)
     self._description = 'ProgramY AIML2.0 Client'
     self._bot_configs = []
     self._bot_configs.append(BotConfiguration("bot"))
     self._bot_selector = None
     self._scheduler = SchedulerConfiguration()
     self._storage = StorageConfiguration()
     self._renderer = None
    def test_add_default_stores_all_on(self):
        store_configs = {}
        StorageConfiguration.add_default_stores_as_yaml(store_configs,
                                                        file=True,
                                                        sqlite=True,
                                                        mongo=True,
                                                        redis=True,
                                                        logger=True)

        self.assertDefaultStoreConfigs(store_configs)
Exemple #6
0
    def test_load_engines_from_config_raise_exception(self):
        storage_config = StorageConfiguration()
        storage_config._entity_store["MOCK"] = storage_config
        storage_config._store_configs["MOCK"] = MockStorageConfiguration(
            "MOCK", throwexcept=True)
        factory = StorageFactory()

        factory.load_engines_from_config(storage_config)

        self.assertFalse(factory.storage_engine_available("MOCK"))
    def test_create_storage_config_file_only(self):
        storage_config = StorageConfiguration()

        config = storage_config.create_storage_config()
        self.assertIsNotNone(config)

        self.assertTrue('file' in config['stores'])
        self.assertFalse('sqlite' in config['stores'])
        self.assertFalse('mongo' in config['stores'])
        self.assertFalse('redis' in config['stores'])
        self.assertFalse('logger' in config['stores'])
Exemple #8
0
    def __init__(self, name):
        BaseContainerConfigurationData.__init__(self, name)
        self._description = 'ProgramY AIML2.0 Client'
        self._renderer = self._get_renderer_class()
        self._scheduler = SchedulerConfiguration()
        self._storage = StorageConfiguration()
        self._email = EmailConfiguration()
        self._triggers = TriggerConfiguration()
        self._responder = PingResponderConfig()

        self._bot_selector = self._get_bot_selector_class()
        bot_config = BotConfiguration('bot')
        self._bot_configs = [bot_config]
    def test_create_storage_config_nothing(self):
        storage_config = StorageConfiguration()

        config = storage_config.create_storage_config(file=False,
                                                      sqlite=False,
                                                      mongo=False,
                                                      redis=False,
                                                      logger=False)
        self.assertIsNotNone(config)

        self.assertFalse('file' in config['stores'])
        self.assertFalse('sqlite' in config['stores'])
        self.assertFalse('mongo' in config['stores'])
        self.assertFalse('redis' in config['stores'])
        self.assertFalse('logger' in config['stores'])
    def test_create_storage_config_all(self):
        storage_config = StorageConfiguration()

        config = storage_config.create_storage_config(file=True,
                                                      sqlite=True,
                                                      mongo=True,
                                                      redis=True,
                                                      logger=True)
        self.assertIsNotNone(config)

        self.assertTrue('file' in config['stores'])
        self.assertTrue('sqlite' in config['stores'])
        self.assertTrue('mongo' in config['stores'])
        self.assertTrue('redis' in config['stores'])
        self.assertTrue('logger' in config['stores'])
    def test_with_no_data_no_config(self):
        yaml = YamlConfigurationFile()
        self.assertIsNotNone(yaml)
        yaml.load_from_text("""
        console:
        """, ConsoleConfiguration(), ".")

        bot_config = yaml.get_section("console")

        storage_config = StorageConfiguration()
        storage_config.load_config_section(yaml, bot_config, ".")

        self.assertIsNotNone(storage_config.entity_store)
        self.assert_entity_store(storage_config)

        self.assertIsNotNone(storage_config.storage_configurations)
        self.assert_storage_configurations(storage_config)
    def test_to_yaml_no_defaults_not_empty(self):
        storage_config = StorageConfiguration()

        StorageConfiguration.add_default_entities(storage_config._entity_store)
        StorageConfiguration.add_default_stores_as_yaml(
            storage_config._store_configs)

        data = {}
        storage_config.to_yaml(data, defaults=False)

        self.assertDefaultEntities(data['entities'])
        self.assertDefaultFileStoreConfig(data['stores'])
    def test_defaults(self):
        storage_config = StorageConfiguration()
        data = {}
        storage_config.to_yaml(data, True)

        StorageConfigurationTests.assert_defaults(self, data)
Exemple #14
0
class ClientConfigurationData(BaseContainerConfigurationData):

    def __init__(self, name):
        BaseContainerConfigurationData.__init__(self, name)
        self._description = 'ProgramY AIML2.0 Client'
        self._bot_configs = []
        self._bot_configs.append(BotConfiguration("bot"))
        self._bot_selector = None
        self._scheduler = SchedulerConfiguration()
        self._storage = StorageConfiguration()
        self._renderer = None

    @property
    def description(self):
        return self._description

    @property
    def configurations(self):
        return self._bot_configs

    @property
    def bot_selector(self):
        return self._bot_selector

    @property
    def scheduler(self):
        return self._scheduler

    @property
    def storage(self):
        return self._storage

    @property
    def renderer(self):
        return self._renderer

    def load_configuration(self, configuration_file, section, bot_root):

        assert(configuration_file is not None)

        if section is not None:
            self._description = configuration_file.get_option(section, "description", missing_value='ProgramY AIML2.0 Client')

            bot_names = configuration_file.get_multi_option(section, "bot", missing_value="bot")
            first = True
            for name in bot_names:
                if first is True:
                    config = self._bot_configs[0]
                    first = False
                else:
                    config = BotConfiguration(name)
                    self._bot_configs.append(config)
                config.load_configuration(configuration_file, bot_root)

            self._bot_selector = configuration_file.get_option(section, "bot_selector", missing_value="programy.clients.client.DefaultBotSelector")

            self._scheduler.load_config_section(configuration_file, section, bot_root)

            self._storage.load_config_section(configuration_file, section, bot_root)

            self._renderer = configuration_file.get_option(section, "renderer")

        else:
            YLogger.warning(self, "No bot name defined for client [%s], defaulting to 'bot'.", self.section_name)
            self._bot_configs[0]._section_name = "bot"
            self._bot_configs[0].load_configuration(configuration_file, bot_root)

    def to_yaml(self, data, defaults=True):

        assert (data is not None)

        if defaults is True:
            data['description'] = 'ProgramY AIML2.0 Client'
            data['bot'] = 'bot'
            data['bot_selector'] = "programy.clients.client.DefaultBotSelector"

            data[self._scheduler.id] = {}
            self._scheduler.to_yaml(data[self._scheduler.id], defaults)


            data['renderer'] = "programy.clients.render.text.TextRenderer"

        else:
            data['description'] = self._description
            data['bot'] = self._bot_configs[0].id
            data['bot_selector'] = self.bot_selector

            data[self._scheduler.id] = {}
            self._scheduler.to_yaml(data[self._scheduler.id], defaults)

            data['renderer'] = self.renderer
    def test_initialise_with_config_sql_only(self):

        yaml = YamlConfigurationFile()
        self.assertIsNotNone(yaml)
        yaml.load_from_text(
            """
        console:
            storage:
                entities:
                    users: sql
                    linked_accounts: sql
                    links: sql
                    properties: sql
                    conversations:   sql
                    categories: sql

                stores:
                    sql:
                        type:   sql
                        config:
                            url: sqlite:///:memory
                            echo: false
                            encoding: utf-8
                            create_db: true
                            drop_all_first: true

        """, ConsoleConfiguration(), ".")

        bot_config = yaml.get_section("console")

        storage_config = StorageConfiguration()
        storage_config.load_config_section(yaml, bot_config, ".")

        factory = StorageFactory()
        factory.load_engines_from_config(storage_config)

        self.assertTrue(factory.storage_engine_available("sql"))

        self.assertFalse(factory.storage_engine_available("mongo"))
        self.assertFalse(factory.storage_engine_available("redis"))
        self.assertFalse(factory.storage_engine_available("file"))
        self.assertFalse(factory.storage_engine_available("logger"))
        self.assertFalse(factory.storage_engine_available("other"))
        self.assertIsNone(factory.storage_engine("other"))

        self.assertTrue(factory.entity_storage_engine_available("users"))
        self.assertIsInstance(factory.entity_storage_engine("users"),
                              SQLStorageEngine)
        self.assertTrue(
            factory.entity_storage_engine_available("linked_accounts"))
        self.assertIsInstance(factory.entity_storage_engine("linked_accounts"),
                              SQLStorageEngine)
        self.assertTrue(factory.entity_storage_engine_available("links"))
        self.assertIsInstance(factory.entity_storage_engine("links"),
                              SQLStorageEngine)
        self.assertTrue(factory.entity_storage_engine_available("properties"))
        self.assertIsInstance(factory.entity_storage_engine("properties"),
                              SQLStorageEngine)
        self.assertTrue(
            factory.entity_storage_engine_available("conversations"))
        self.assertIsInstance(factory.entity_storage_engine("conversations"),
                              SQLStorageEngine)
        self.assertTrue(factory.entity_storage_engine_available("categories"))
        self.assertIsInstance(factory.entity_storage_engine("categories"),
                              SQLStorageEngine)
        self.assertFalse(factory.entity_storage_engine_available("other"))
        self.assertIsNone(factory.entity_storage_engine("other"))
    def test_initialise_with_config_mongo(self):

        yaml = YamlConfigurationFile()
        self.assertIsNotNone(yaml)
        yaml.load_from_text(
            """
        console:
            storage:
                entities:
                    users: mongo
                    linked_accounts: mongo
                    links: mongo
                    properties: mongo
                    conversations:   mongo
                    categories: mongo

                stores:
                    mongo:
                        type:   mongo
                        config:
                            url: mongodb://localhost:27017/
                            database: programy
                            drop_all_first: true

        """, ConsoleConfiguration(), ".")

        bot_config = yaml.get_section("console")

        storage_config = StorageConfiguration()
        storage_config.load_config_section(yaml, bot_config, ".")

        factory = StorageFactory()
        factory.load_engines_from_config(storage_config)

        self.assertTrue(factory.storage_engine_available("mongo"))

        self.assertFalse(factory.storage_engine_available("sql"))
        self.assertFalse(factory.storage_engine_available("redis"))
        self.assertFalse(factory.storage_engine_available("file"))
        self.assertFalse(factory.storage_engine_available("logger"))
        self.assertFalse(factory.storage_engine_available("other"))
        self.assertIsNone(factory.storage_engine("other"))

        self.assertTrue(factory.entity_storage_engine_available("users"))
        self.assertIsInstance(factory.entity_storage_engine("users"),
                              MongoStorageEngine)
        self.assertTrue(
            factory.entity_storage_engine_available("linked_accounts"))
        self.assertIsInstance(factory.entity_storage_engine("linked_accounts"),
                              MongoStorageEngine)
        self.assertTrue(factory.entity_storage_engine_available("links"))
        self.assertIsInstance(factory.entity_storage_engine("links"),
                              MongoStorageEngine)
        self.assertTrue(factory.entity_storage_engine_available("properties"))
        self.assertIsInstance(factory.entity_storage_engine("properties"),
                              MongoStorageEngine)
        self.assertTrue(
            factory.entity_storage_engine_available("conversations"))
        self.assertIsInstance(factory.entity_storage_engine("conversations"),
                              MongoStorageEngine)
        self.assertTrue(factory.entity_storage_engine_available("categories"))
        self.assertIsInstance(factory.entity_storage_engine("categories"),
                              MongoStorageEngine)
        self.assertFalse(factory.entity_storage_engine_available("other"))
        self.assertIsNone(factory.entity_storage_engine("other"))
    def test_initialise_with_config_mixed(self):

        yaml = YamlConfigurationFile()
        self.assertIsNotNone(yaml)
        yaml.load_from_text(
            """
        console:
            storage:
                entities:
                    users: sql
                    linked_accounts: sql
                    links: sql
                    properties: redis
                    conversations:   mongo
                    categories: sql

                stores:
                    sql:
                        type:   sql
                        config:
                            url: sqlite:///:memory
                            echo: false
                            encoding: utf-8
                            create_db: true
                            drop_all_first: true

                    mongo:
                        type:   mongo
                        config:
                            url: mongodb://localhost:27017/
                            database: programy
                            drop_all_first: true

                    redis:
                        type:   redis
                        config:
                            host: localhost
                            port: 6379
                            password: null
                            db: 0
                            prefix: programy
                            drop_all_first: True

                    file:
                        type:   file
                        config:
                            storage_dir: ./storage
                            properties_storage: ./storage/properties
                            conversations_storage: ./storage/conversations

                    logger:
                        type:   logger
                        config:
                            conversation_logger: conversation

        """, ConsoleConfiguration(), ".")

        bot_config = yaml.get_section("console")

        storage_config = StorageConfiguration()
        storage_config.load_config_section(yaml, bot_config, ".")

        factory = StorageFactory()
        factory.load_engines_from_config(storage_config)

        self.assertTrue(factory.storage_engine_available("sql"))
        self.assertIsInstance(factory.storage_engine("sql"),
                              MongoStorageEngine)
        self.assertTrue(factory.storage_engine_available("mongo"))
        self.assertIsInstance(factory.storage_engine("mongo"),
                              MongoStorageEngine)
        self.assertTrue(factory.storage_engine_available("redis"))
        self.assertIsInstance(factory.storage_engine("redis"),
                              RedisStorageEngine)
        self.assertTrue(factory.storage_engine_available("file"))
        self.assertIsInstance(factory.storage_engine("file"),
                              FileStorageEngine)
        self.assertTrue(factory.storage_engine_available("logger"))
        self.assertIsInstance(factory.storage_engine("logger"),
                              LoggerStorageEngine)
        self.assertFalse(factory.storage_engine_available("other"))
        self.assertIsNone(factory.storage_engine("other"))

        self.assertTrue(factory.entity_storage_engine_available("users"))
        self.assertIsInstance(factory.entity_storage_engine("users"),
                              SQLStorageEngine)
        self.assertTrue(
            factory.entity_storage_engine_available("linked_accounts"))
        self.assertIsInstance(factory.entity_storage_engine("linked_accounts"),
                              SQLStorageEngine)
        self.assertTrue(factory.entity_storage_engine_available("links"))
        self.assertIsInstance(factory.entity_storage_engine("links"),
                              SQLStorageEngine)
        self.assertTrue(factory.entity_storage_engine_available("properties"))
        self.assertIsInstance(factory.entity_storage_engine("properties"),
                              RedisStorageEngine)
        self.assertTrue(
            factory.entity_storage_engine_available("conversations"))
        self.assertIsInstance(factory.entity_storage_engine("conversations"),
                              MongoStorageEngine)
        self.assertTrue(factory.entity_storage_engine_available("categories"))
        self.assertIsInstance(factory.entity_storage_engine("categories"),
                              SQLStorageEngine)
        self.assertFalse(factory.entity_storage_engine_available("other"))
        self.assertIsNone(factory.entity_storage_engine("other"))
    def test_initialise_with_config_file_only(self):

        yaml = YamlConfigurationFile()
        self.assertIsNotNone(yaml)
        yaml.load_from_text(
            """
        console:
            storage:
                entities:
                    users: file
                    linked_accounts: file
                    links: file
                    properties: file
                    conversations:   file
                    categories: file

                stores:
                    file:
                        type:   file
                        config:
                            storage_dir: ./storage
                            properties_storage: ./storage/properties
                            conversations_storage: ./storage/conversations

        """, ConsoleConfiguration(), ".")

        bot_config = yaml.get_section("console")

        storage_config = StorageConfiguration()
        storage_config.load_config_section(yaml, bot_config, ".")

        factory = StorageFactory()
        factory.load_engines_from_config(storage_config)

        self.assertFalse(factory.storage_engine_available("sql"))
        self.assertFalse(factory.storage_engine_available("mongo"))
        self.assertFalse(factory.storage_engine_available("redis"))
        self.assertFalse(factory.storage_engine_available("logger"))

        self.assertTrue(factory.storage_engine_available("file"))

        self.assertTrue(factory.entity_storage_engine_available("users"))
        self.assertIsInstance(factory.entity_storage_engine("users"),
                              FileStorageEngine)
        self.assertTrue(
            factory.entity_storage_engine_available("linked_accounts"))
        self.assertIsInstance(factory.entity_storage_engine("linked_accounts"),
                              FileStorageEngine)
        self.assertTrue(factory.entity_storage_engine_available("links"))
        self.assertIsInstance(factory.entity_storage_engine("links"),
                              FileStorageEngine)
        self.assertTrue(factory.entity_storage_engine_available("properties"))
        self.assertIsInstance(factory.entity_storage_engine("properties"),
                              FileStorageEngine)
        self.assertTrue(
            factory.entity_storage_engine_available("conversations"))
        self.assertIsInstance(factory.entity_storage_engine("conversations"),
                              FileStorageEngine)
        self.assertTrue(factory.entity_storage_engine_available("categories"))
        self.assertIsInstance(factory.entity_storage_engine("categories"),
                              FileStorageEngine)
        self.assertFalse(factory.entity_storage_engine_available("other"))
        self.assertIsNone(factory.entity_storage_engine("other"))
Exemple #19
0
    def test_with_data(self):
        yaml = YamlConfigurationFile()
        self.assertIsNotNone(yaml)
        yaml.load_from_text(
            """
        console:
            storage:
                entities:
                    users: sqlite
                    linked_accounts: sqlite
                    links: sqlite

                    categories: file
                    errors: file
                    duplicates: file
                    learnf: file

                    conversations: file

                    maps: file
                    sets: file
                    rdf: file

                    denormal: file
                    normal: file
                    gender: file
                    person: file
                    person2: file
                    regex_templates: file

                    properties: file
                    variables: file
                    defaults: file

                    twitter: file

                    spelling_corpus: file

                    license_keys: file

                    template_nodes: file
                    pattern_nodes: file

                    binaries: file
                    braintree: file

                    preprocessors: file
                    postprocessors: file

                    usergroups: file

                    triggers: file

                stores:
                    sqlite:
                        type:   sql
                        config:
                            url: sqlite:///:memory
                            echo: false
                            encoding: utf-8
                            create_db: true
                            drop_all_first: true

                    mongo:
                        type:   mongo
                        config:
                            url: mongodb://localhost:27017/
                            database: programy
                            drop_all_first: true

                    redis:
                        type:   redis
                        config:
                            host: localhost
                            port: 6379
                            password: None
                            db: 0
                            prefix: programy
                            drop_all_first: True

                    file:
                        type:   file
                        config:
                            properties_storage:
                                file: ./storage/properties
                            conversations_storage:
                                dir: ./storage/conversations

                    logger:
                        type:   logger
                        config:
                            conversation_logger: conversation

        """, ConsoleConfiguration(), ".")

        bot_config = yaml.get_section("console")

        storage_config = StorageConfiguration()
        storage_config.load_config_section(yaml, bot_config, ".")

        self.assertIsNotNone(storage_config.entity_store)
        self.assert_entity_store(storage_config)

        self.assertIsNotNone(storage_config.storage_configurations)
        self.assert_storage_configurations(storage_config)
class ClientConfigurationData(BaseContainerConfigurationData):
    def __init__(self, name):
        BaseContainerConfigurationData.__init__(self, name)
        self._description = 'ProgramY AIML2.0 Client'
        self._bot_configs = []
        self._bot_configs.append(BotConfiguration("bot"))
        self._bot_selector = None
        self._renderer = None
        self._scheduler = SchedulerConfiguration()
        self._storage = StorageConfiguration()
        self._email = EmailConfiguration()
        self._triggers = TriggerConfiguration()

    @property
    def description(self):
        return self._description

    @property
    def configurations(self):
        return self._bot_configs

    @property
    def bot_selector(self):
        return self._bot_selector

    @property
    def scheduler(self):
        return self._scheduler

    @property
    def storage(self):
        return self._storage

    @property
    def renderer(self):
        return self._renderer

    @property
    def email(self):
        return self._email

    @property
    def triggers(self):
        return self._triggers

    def check_for_license_keys(self, license_keys):
        BaseContainerConfigurationData.check_for_license_keys(
            self, license_keys)

    def load_configuration(self,
                           configuration_file,
                           bot_root,
                           subs: Substitutions = None):
        client = configuration_file.get_section(self.section_name)
        if client is None:
            YLogger.error(
                None, 'Client section named [%s] not found, trying "client"',
                self.section_name)
            client = configuration_file.get_section('client')

        if client is not None:
            self.load_configuration_section(configuration_file, client,
                                            bot_root, subs)
        else:
            YLogger.error(None, 'No client section not found!')

    def load_configuration_section(self,
                                   configuration_file,
                                   section,
                                   bot_root,
                                   subs: Substitutions = None):

        assert (configuration_file is not None)

        if section is not None:
            self._description = configuration_file.get_option(
                section,
                "description",
                missing_value='ProgramY AIML2.0 Client',
                subs=subs)

            bot_names = configuration_file.get_multi_option(
                section, "bot", missing_value="bot", subs=subs)
            first = True
            for name in bot_names:
                if first is True:
                    config = self._bot_configs[0]
                    first = False

                else:
                    config = BotConfiguration(name)
                    self._bot_configs.append(config)

                config.load_configuration(configuration_file,
                                          bot_root,
                                          subs=subs)

            self._bot_selector = configuration_file.get_option(
                section,
                "bot_selector",
                missing_value="programy.clients.client.DefaultBotSelector",
                subs=subs)

            self._scheduler.load_config_section(configuration_file,
                                                section,
                                                bot_root,
                                                subs=subs)

            self._storage.load_config_section(configuration_file,
                                              section,
                                              bot_root,
                                              subs=subs)

            self._renderer = configuration_file.get_option(section,
                                                           "renderer",
                                                           subs=subs)

            self._email.load_config_section(configuration_file,
                                            section,
                                            bot_root,
                                            subs=subs)

            self._triggers.load_config_section(configuration_file,
                                               section,
                                               bot_root,
                                               subs=subs)

        else:
            YLogger.warning(
                self,
                "No bot name defined for client [%s], defaulting to 'bot'.",
                self.section_name)
            self._bot_configs[0]._section_name = "bot"
            self._bot_configs[0].load_configuration(configuration_file,
                                                    bot_root,
                                                    subs=subs)

    def to_yaml(self, data, defaults=True):

        assert (data is not None)

        if defaults is True:
            data['description'] = 'ProgramY AIML2.0 Client'
            data['bot'] = 'bot'
            data['bot_selector'] = "programy.clients.client.DefaultBotSelector"
            data['renderer'] = "programy.clients.render.text.TextRenderer"
        else:
            data['description'] = self._description
            data['bot'] = self._bot_configs[0].id
            data['bot_selector'] = self.bot_selector
            data['renderer'] = self.renderer

        data[self._scheduler.id] = {}
        self._scheduler.to_yaml(data[self._scheduler.id], defaults)

        data['email'] = {}
        self._email.to_yaml(data['email'], defaults)

        data['triggers'] = {}
        self._triggers.to_yaml(data['triggers'], defaults)
Exemple #21
0
class ClientConfigurationData(BaseContainerConfigurationData):
    def __init__(self, name):
        BaseContainerConfigurationData.__init__(self, name)
        self._description = 'ProgramY AIML2.0 Client'
        self._renderer = self._get_renderer_class()
        self._scheduler = SchedulerConfiguration()
        self._storage = StorageConfiguration()
        self._email = EmailConfiguration()
        self._triggers = TriggerConfiguration()
        self._responder = PingResponderConfig()

        self._bot_selector = self._get_bot_selector_class()
        bot_config = BotConfiguration('bot')
        self._bot_configs = [bot_config]

    def _get_renderer_class(self):
        return "programy.clients.render.text.TextRenderer"

    def _get_bot_selector_class(self):
        return "programy.clients.botfactory.DefaultBotSelector"

    @property
    def description(self):
        return self._description

    @property
    def configurations(self):
        return self._bot_configs

    @property
    def bot_selector(self):
        return self._bot_selector

    @property
    def scheduler(self):
        return self._scheduler

    @property
    def storage(self):
        return self._storage

    @property
    def renderer(self):
        return self._renderer

    @property
    def email(self):
        return self._email

    @property
    def triggers(self):
        return self._triggers

    @property
    def responder(self):
        return self._responder

    def load_configuration(self,
                           configuration_file,
                           bot_root,
                           subs: Substitutions = None):
        client = configuration_file.get_section(self.section_name)
        if client is None:
            YLogger.error(
                None, 'Client section named [%s] not found, trying "client"',
                self.section_name)
            client = configuration_file.get_section('client')

        if client is not None:
            self.load_configuration_section(configuration_file, client,
                                            bot_root, subs)

        else:
            YLogger.error(None, 'No client section not found!')

    def load_configuration_section(self,
                                   configuration_file,
                                   section,
                                   bot_root,
                                   subs: Substitutions = None):

        assert configuration_file is not None
        assert section is not None

        self._description = configuration_file.get_option(
            section,
            "description",
            missing_value='ProgramY AIML2.0 Client',
            subs=subs)

        self._scheduler.load_config_section(configuration_file,
                                            section,
                                            bot_root,
                                            subs=subs)

        self._storage.load_config_section(configuration_file,
                                          section,
                                          bot_root,
                                          subs=subs)

        self._renderer = configuration_file.get_option(section,
                                                       "renderer",
                                                       subs=subs)

        self._email.load_config_section(configuration_file,
                                        section,
                                        bot_root,
                                        subs=subs)

        self._triggers.load_config_section(configuration_file,
                                           section,
                                           bot_root,
                                           subs=subs)

        self._responder.load_config_section(configuration_file,
                                            section,
                                            bot_root,
                                            subs=subs)

        self._load_bot_configurations(configuration_file, section, bot_root,
                                      subs)

    def _load_bot_configurations(self, configuration_file, section, bot_root,
                                 subs):
        bots = configuration_file.get_section("bots", section)
        if bots is not None:
            bot_keys = configuration_file.get_keys(bots)
            first = True
            for name in bot_keys:
                if first is True:
                    self._bot_configs.clear()
                    first = False
                bot_config = configuration_file.get_section(name, bots)
                config = BotConfiguration(name)
                config.load_configuration_section(configuration_file,
                                                  bot_config,
                                                  bot_root,
                                                  subs=subs)
                self._bot_configs.append(config)

        if len(self._bot_configs) == 0:
            YLogger.warning(
                self,
                "No bot name defined for client [%s], defaulting to 'bot'.",
                self.section_name)
            self._bot_configs.append(BotConfiguration("bot"))
            self._bot_configs[0].configurations.append(
                BrainConfiguration("brain"))

        self._bot_selector = configuration_file.get_option(
            section,
            "bot_selector",
            missing_value="programy.clients.botfactory.DefaultBotSelector",
            subs=subs)

    def to_yaml(self, data, defaults=True):

        assert data is not None

        if defaults is True:
            data['description'] = 'ProgramY AIML2.0 Client'
            data[
                'bot_selector'] = "programy.clients.botfactory.DefaultBotSelector"

            data['scheduler'] = {}
            self._scheduler.to_yaml(data['scheduler'], defaults)

            data['email'] = {}
            self._email.to_yaml(data['email'], defaults)

            data['triggers'] = {}
            self._triggers.to_yaml(data['triggers'], defaults)

            data['responder'] = {}
            self._responder.to_yaml(data['responder'], defaults)

            data['renderer'] = "programy.clients.render.text.TextRenderer"

            data['storage'] = {}
            self._storage.to_yaml(data['storage'], defaults)

            data['bots'] = {}
            data['bots']['bot'] = {}
            bot_config = BotConfiguration('bot')
            bot_config.to_yaml(data['bots']['bot'], defaults)

        else:
            data['description'] = self._description
            data['bot_selector'] = self.bot_selector

            data[self._scheduler.id] = {}
            self._scheduler.to_yaml(data[self._scheduler.id], defaults)

            data['email'] = {}
            self._email.to_yaml(data['email'], defaults)

            data['triggers'] = {}
            self._triggers.to_yaml(data['triggers'], defaults)

            data['responder'] = {}
            self._responder.to_yaml(data['responder'], defaults)

            data['renderer'] = self.renderer

            data['storage'] = {}
            self._storage.to_yaml(data['storage'], defaults)

            data['bots'] = {}
            for botconfig in self._bot_configs:
                data['bots'][botconfig.id] = {}
                botconfig.to_yaml(data['bots'][botconfig.id], defaults)