<commit_before>import argparse
import logging
from collections import UserDict

from sqlalchemy.orm import joinedload

from pajbot.managers.db import DBManager
from pajbot.models.command import Command
from pajbot.models.command import CommandData
from pajbot.models.command import CommandExample
from pajbot.models.command import parse_command_for_web
from pajbot.utils import find

log = logging.getLogger(__name__)


class CommandManager(UserDict):
    """ This class is responsible for compiling commands from multiple sources
    into one easily accessible source.
    The following sources are used:
     - internal_commands = Commands that are added in source
     - db_commands = Commands that are loaded from the database
     - module_commands = Commands that are loaded from enabled modules

    """

    def __init__(self, socket_manager=None, module_manager=None, bot=None):
        UserDict.__init__(self)
        self.db_session = DBManager.create_session()

        self.internal_commands = {}
        self.db_commands = {}
        self.module_commands = {}

        self.bot = bot
        self.module_manager = module_manager

        if socket_manager:
            socket_manager.add_handler('module.update', self.on_module_reload)
            socket_manager.add_handler('command.update', self.on_command_update)
            socket_manager.add_handler('command.remove', self.on_command_remove)

    def on_module_reload(self, data, conn):
        log.debug('Rebuilding commands...')
        self.rebuild()
        log.debug('Done rebuilding commands')

    def on_command_update(self, data, conn):
        try:
            command_id = int(data['command_id'])
        except (KeyError, ValueError):
            log.warn('No command ID found in on_command_update')
            return False

        command = find(lambda command: command.id == command_id, self.db_commands.values())
        if command is not None:
            self.remove_command_aliases(command)

        self.load_by_id(command_id)

        log.debug('Reloaded command with id {}'.format(command_id))

        self.rebuild()

    def on_command_remove(self, data, conn):
        try:
            command_id = int(data['command_id'])
        except (KeyError, ValueError):
            log.warn('No command ID found in on_command_update')
            return False

        command = find(lambda command: command.id == command_id, self.db_commands.values())
        if command is None:
            log.warn('Invalid ID sent to on_command_update')
            return False

        self.db_session.expunge(command.data)
        self.remove_command_aliases(command)

        log.debug('Remove command with id {}'.format(command_id))

        self.rebuild()

    def __del__(self):
        self.db_session.close()

    def commit(self):
        self.db_session.commit()

    def load_internal_commands(self, **options):
        if len(self.internal_commands) > 0:
            return self.internal_commands

        self.internal_commands = {}

        self.internal_commands['quit'] = Command.pajbot_command(self.bot, 'quit',
                level=1000,
                command='quit',
                description='Shut down the bot, this will most definitely restart it if set up properly')

        self.internal_commands['ceaseallactionscurrentlybeingacteduponwiththecodeandiapologizeforbeingawhitecisgenderedmaleinthepatriarchy'] = self.internal_commands['quit']

        self.internal_commands['twitterfollow'] = Command.dispatch_command('twitter_follow',
                level=1000,
                description='Start listening for tweets for the given user',
                examples=[
                    CommandExample(None, 'Default usage',
                        chat='user:!twitterfollow forsensc2\n'<commit_msg>added !1quit as an alias to !quit<commit_after>import argparse
import logging
from collections import UserDict

from sqlalchemy.orm import joinedload

from pajbot.managers.db import DBManager
from pajbot.models.command import Command
from pajbot.models.command import CommandData
from pajbot.models.command import CommandExample
from pajbot.models.command import parse_command_for_web
from pajbot.utils import find

log = logging.getLogger(__name__)


class CommandManager(UserDict):
    """ This class is responsible for compiling commands from multiple sources
    into one easily accessible source.
    The following sources are used:
     - internal_commands = Commands that are added in source
     - db_commands = Commands that are loaded from the database
     - module_commands = Commands that are loaded from enabled modules

    """

    def __init__(self, socket_manager=None, module_manager=None, bot=None):
        UserDict.__init__(self)
        self.db_session = DBManager.create_session()

        self.internal_commands = {}
        self.db_commands = {}
        self.module_commands = {}

        self.bot = bot
        self.module_manager = module_manager

        if socket_manager:
            socket_manager.add_handler('module.update', self.on_module_reload)
            socket_manager.add_handler('command.update', self.on_command_update)
            socket_manager.add_handler('command.remove', self.on_command_remove)

    def on_module_reload(self, data, conn):
        log.debug('Rebuilding commands...')
        self.rebuild()
        log.debug('Done rebuilding commands')

    def on_command_update(self, data, conn):
        try:
            command_id = int(data['command_id'])
        except (KeyError, ValueError):
            log.warn('No command ID found in on_command_update')
            return False

        command = find(lambda command: command.id == command_id, self.db_commands.values())
        if command is not None:
            self.remove_command_aliases(command)

        self.load_by_id(command_id)

        log.debug('Reloaded command with id {}'.format(command_id))

        self.rebuild()

    def on_command_remove(self, data, conn):
        try:
            command_id = int(data['command_id'])
        except (KeyError, ValueError):
            log.warn('No command ID found in on_command_update')
            return False

        command = find(lambda command: command.id == command_id, self.db_commands.values())
        if command is None:
            log.warn('Invalid ID sent to on_command_update')
            return False

        self.db_session.expunge(command.data)
        self.remove_command_aliases(command)

        log.debug('Remove command with id {}'.format(command_id))

        self.rebuild()

    def __del__(self):
        self.db_session.close()

    def commit(self):
        self.db_session.commit()

    def load_internal_commands(self, **options):
        if len(self.internal_commands) > 0:
            return self.internal_commands

        self.internal_commands = {}

        self.internal_commands['quit'] = Command.pajbot_command(self.bot, 'quit',
                level=1000,
                command='quit',
                description='Shut down the bot, this will most definitely restart it if set up properly')

        self.internal_commands['1quit'] = self.internal_commands['quit']
        self.internal_commands['ceaseallactionscurrentlybeingacteduponwiththecodeandiapologizeforbeingawhitecisgenderedmaleinthepatriarchy'] = self.internal_commands['quit']

        self.internal_commands['twitterfollow'] = Command.dispatch_command('twitter_follow',
                level=1000,
                description='Start listening for tweets for the given user',
                examples=[
                    CommandExample(None, 'Default usage',
                        chat='user:!twitterfollow forsensc2\n'
{'fraction_non_alphanumeric': 0.0860703621965468, 'fraction_numerical': 0.0028560301181357914, 'mean_word_length': 2.8100890207715135, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, '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': '7628875', 'n_tokens_mistral': 2124, 'n_tokens_neox': 2005, 'n_words': 505}