<commit_before>#!/usr/bin/env python
# -*- coding: utf-8 -*-

""" Slack bot for Overcast Network """

import sys
import time
import logging
import logging.config
import json
import signal
import yaml
import os
import inspect
from slackclient import SlackClient
from plugin import Plugin, CommandPlugin

# Log to file and SDOUT
logging.config.fileConfig('logging.conf')
log = logging.getLogger(__name__)
logging.captureWarnings(True)


class Nimbus(object):
    """
    Main bot class
    """

    def get_config(self, filename):
        """ Gets the bot config file """
        try:
            return yaml.safe_load(file(filename))
        except IOError as e:
            raise SystemExit("Couldn't open configuration file: %s" % e)

    def process_event(self, event):
        """
        Processes an event and invokes plugins
        """

        for plugin in filter(lambda p: p.event_type == event['type'], self.plugins):
            # JSON Response for all API calls
            response = dict(username=self.username, icon_emoji=self.icon_emoji)
            if 'channel' in event:
                response.update({'channel': event['channel']})

            # Copy the event in order to prevent changes from propagating to other plugins
            # Some plugins (like CommandPlugins) decide to edit the event in-place
            plugin.on_event(self, dict(event), response)

    def run(self):
        """
        Main loop
        """
        log.info("Starting bot loop...")
        while True:
            events = self.sc.rtm_read()
            for event in events:
                # Don't listen to the bot's own messages or other bot messages
                if event.get('subtype') == 'bot_message':
                    continue

                # Don't listen to hidden events such as 'message_changed' or 'message_deleted'
                # Some of these message subtypes don't have text which we don't want to parse
                if event.get('hidden'):
                    continue

                self.process_event(event)

            time.sleep(self.polling_interval)

    def register_plugin(self, plugin):
        """
        Registers the specified plugin with the bot 
        """
        if not type(plugin) is type or not issubclass(plugin, Plugin):
            log.warning('Module %s not subclass of Plugin! Skipping...' % plugin.__name__)
            return

        # Instantiate class and add to plugins list
        self.plugins.append(plugin())
        log.info('Successfully registered plugin \'%s\'' % plugin.__name__)

    def load_plugins(self):
        """
        Loads all plugins from the /plugins/ directory
        """
        log.info('Registering plugins...')
        plugin_directory = 'plugins'  # TODO Config setting?
        # Loop through files in plugin directory
        for f in os.listdir(plugin_directory):
            module_name, extension = os.path.splitext(f)
            if extension == ".py":
                module_path = '%s.%s' % (plugin_directory, module_name)
                imported = __import__(module_path, fromlist=[module_name])

                # Find all the Plugin classes in the module
                # This means you could have mltiple plugins per module
                class_filter = lambda c: inspect.isclass(c) and c.__module__ == module_path and issubclass(c, Plugin)
                classes = inspect.getmembers(imported, class_filter)

                # Register all found plugin classes
                for name, klass in classes:
                    self.register_plugin(klass)

    def get_command(self, trigger):
        """
        Returns a command plugin instance contains the specified trigger
        (if there is one)
        """
        # TODO This might get a bit slow when we have a lot of plugins
        # Consider another data structure for storing loaded plugins

        for plugin in filter(lambda p: isinstance(p, CommandPlugin), self.plugins):
            for trig in plugin.triggers:
                if trigger == trig:
                    return plugin

    def __init__(self, config_name):
        """
        Bot constructor
        """
        log.info("Initializing Nimbus instance...")
        config = self.get_config(config_name)

        self.username = config.get('username', 'nimbus')
        self.icon_emoji = ':' + config.get('icon_emoji', 'cloud') + ':'
        self.polling_interval = config.get('polling_interval', 1)
        self.command_prefix = config.get('command_prefix', '!')
        self.plugins = []

        self.token = config.get('token')<commit_msg>Log number of loaded plugins on startup - Also remove redundant plugin checks<commit_after>#!/usr/bin/env python
# -*- coding: utf-8 -*-

""" Slack bot for Overcast Network """

import sys
import time
import logging
import logging.config
import json
import signal
import yaml
import os
import inspect
from slackclient import SlackClient
from plugin import Plugin, CommandPlugin

# Log to file and SDOUT
logging.config.fileConfig('logging.conf')
log = logging.getLogger(__name__)
logging.captureWarnings(True)


class Nimbus(object):
    """
    Main bot class
    """

    def get_config(self, filename):
        """ Gets the bot config file """
        try:
            return yaml.safe_load(file(filename))
        except IOError as e:
            raise SystemExit("Couldn't open configuration file: %s" % e)

    def process_event(self, event):
        """
        Processes an event and invokes plugins
        """

        for plugin in filter(lambda p: p.event_type == event['type'], self.plugins):
            # JSON Response for all API calls
            response = dict(username=self.username, icon_emoji=self.icon_emoji)
            if 'channel' in event:
                response.update({'channel': event['channel']})

            # Copy the event in order to prevent changes from propagating to other plugins
            # Some plugins (like CommandPlugins) decide to edit the event in-place
            plugin.on_event(self, dict(event), response)

    def run(self):
        """
        Main loop
        """
        log.info("Starting bot loop...")
        while True:
            events = self.sc.rtm_read()
            for event in events:
                # Don't listen to the bot's own messages or other bot messages
                if event.get('subtype') == 'bot_message':
                    continue

                # Don't listen to hidden events such as 'message_changed' or 'message_deleted'
                # Some of these message subtypes don't have text which we don't want to parse
                if event.get('hidden'):
                    continue

                self.process_event(event)

            time.sleep(self.polling_interval)

    def register_plugin(self, plugin):
        """
        Registers the specified plugin with the bot 
        """
        # Instantiate class and add to plugins list
        self.plugins.append(plugin())
        log.info('Successfully registered plugin \'%s\'' % plugin.__name__)

    def load_plugins(self):
        """
        Loads all plugins from the /plugins/ directory
        """
        log.info('Registering plugins...')
        plugin_directory = 'plugins'  # TODO Config setting?
        num_plugins = 0
        # Loop through files in plugin directory
        for f in os.listdir(plugin_directory):
            module_name, extension = os.path.splitext(f)
            if extension == ".py":
                module_path = '%s.%s' % (plugin_directory, module_name)
                imported = __import__(module_path, fromlist=[module_name])

                # Find all the Plugin classes in the module
                # This means you could have multiple plugins per module
                class_filter = lambda c: inspect.isclass(c) and c.__module__ == module_path and issubclass(c, Plugin)
                classes = inspect.getmembers(imported, class_filter)

                # Register all found plugin classes
                for name, klass in classes:
                    self.register_plugin(klass)
                    num_plugins += 1
        log.info('Loaded %s plugins!' % num_plugins)

    def get_command(self, trigger):
        """
        Returns a command plugin instance contains the specified trigger
        (if there is one)
        """
        # TODO This might get a bit slow when we have a lot of plugins
        # Consider another data structure for storing loaded plugins

        for plugin in filter(lambda p: isinstance(p, CommandPlugin), self.plugins):
            for trig in plugin.triggers:
                if trigger == trig:
                    return plugin

    def __init__(self, config_name):
        """
        Bot constructor
        """
        log.info("Initializing Nimbus instance...")
        config = self.get_config(config_name)

        self.username = config.get('username', 'nimbus')
        self.icon_emoji = ':' + config.get('icon_emoji', 'cloud') + ':'
        self.polling_interval = config.get('polling_interval', 1)
        self.command_prefix = config.get('command_prefix', '!')
        self.plugins = []

        self.token = config.get('token')
{'fraction_non_alphanumeric': 0.09282056868939971, 'fraction_numerical': 0.0006536659766859135, 'mean_word_length': 2.1023994592767825, 'pattern_counts': {'":': 2, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1133829', 'n_tokens_mistral': 2413, 'n_tokens_neox': 2287, 'n_words': 778}