Beispiel #1
0
def test_unregister_url_callback_no_memory(tmpconfig):
    """Test unregister_url_callback behavior when bot.memory empty"""
    test_pattern = r'https://(www\.)?example\.com'

    def url_handler(*args, **kwargs):
        return None

    sopel = bot.Sopel(tmpconfig, daemon=False)
    sopel.unregister_url_callback(test_pattern, url_handler)
Beispiel #2
0
def run(config, pid_file, daemon=False):
    import sopel.bot as bot
    import sopel.logger
    from sopel.tools import stderr
    delay = 20
    # Inject ca_certs from config to web for SSL validation of web requests
    if not config.core.ca_certs:
        stderr('Could not open CA certificates file. SSL will not '
               'work properly.')

    def signal_handler(sig, frame):
        if sig == signal.SIGUSR1 or sig == signal.SIGTERM or sig == signal.SIGINT:
            stderr('Got quit signal, shutting down.')
            p.quit('Closing')

    # Define empty variable `p` for bot
    p = None
    while True:
        if p and p.hasquit:  # Check if `hasquit` was set for bot during disconnected phase
            break
        try:
            p = bot.Sopel(config, daemon=daemon)
            if hasattr(signal, 'SIGUSR1'):
                signal.signal(signal.SIGUSR1, signal_handler)
            if hasattr(signal, 'SIGTERM'):
                signal.signal(signal.SIGTERM, signal_handler)
            if hasattr(signal, 'SIGINT'):
                signal.signal(signal.SIGINT, signal_handler)
            sopel.logger.setup_logging(p)
            p.run(config.core.host, int(config.core.port))
        except KeyboardInterrupt:
            break
        except Exception:  # TODO: Be specific
            trace = traceback.format_exc()
            try:
                stderr(trace)
            except Exception:  # TODO: Be specific
                pass
            logfile = open(os.path.join(config.core.logdir, 'exceptions.log'),
                           'a')
            logfile.write('Critical exception in core')
            logfile.write(trace)
            logfile.write('----------------------------------------\n\n')
            logfile.close()
            os.unlink(pid_file)
            os._exit(1)

        if not isinstance(delay, int):
            break
        if p.hasquit:
            break
        stderr('Warning: Disconnected. Reconnecting in %s seconds...' % delay)
        time.sleep(delay)
    os.unlink(pid_file)
    os._exit(0)
Beispiel #3
0
def test_search_url_callbacks(tmpconfig):
    """Test search_url_callbacks for a registered URL."""
    sopel = bot.Sopel(tmpconfig, daemon=False)

    def url_handler(*args, **kwargs):
        return None

    sopel.register_url_callback(r'https://example\.com', url_handler)
    results = list(sopel.search_url_callbacks('https://example.com'))
    assert len(results) == 1, 'Expected 1 handler; found %d' % len(results)
    assert url_handler in results[0], 'Once registered, handler must be found'
Beispiel #4
0
def run(settings, pid_file, daemon=False):
    """Run the bot with these ``settings``.

    :param settings: settings with which to run the bot
    :type settings: :class:`sopel.config.Config`
    :param str pid_file: path to the bot's PID file
    :param bool daemon: tell if the bot should be run as a daemon
    """
    delay = 20

    # Acts as a welcome message, showing the program and platform version at start
    print_version()
    # Also show the location of the config file used to load settings
    print("\nLoaded config file: {}".format(settings.filename))

    # Define empty variable `p` for bot
    p = None
    while True:
        if p and p.hasquit:  # Check if `hasquit` was set for bot during disconnected phase
            break
        try:
            p = bot.Sopel(settings, daemon=daemon)
            p.setup()
        except KeyboardInterrupt:
            tools.stderr('Bot setup interrupted')
            break
        except Exception:
            # In that case, there is nothing we can do.
            # If the bot can't setup itself, then it won't run.
            # This is a critical case scenario, where the user should have
            # direct access to the exception traceback right in the console.
            # Besides, we can't know if logging has been set up or not, so
            # we can't rely on that here.
            tools.stderr('Unexpected error in bot setup')
            raise

        try:
            p.run(settings.core.host, int(settings.core.port))
        except KeyboardInterrupt:
            break
        except Exception:
            err_log = logging.getLogger('sopel.exceptions')
            err_log.exception('Critical exception in core')
            err_log.error('----------------------------------------')
            return ERR_CODE

        if p.wantsrestart:
            return -1
        if p.hasquit:
            return 0

        LOGGER.warning('Disconnected. Reconnecting in %s seconds...', delay)
        time.sleep(delay)
Beispiel #5
0
def test_reload_plugin_unregistered_plugin(tmpconfig):
    sopel = bot.Sopel(tmpconfig, daemon=False)
    sopel.scheduler.stop()
    sopel.scheduler.join(timeout=10)
    plugin = sopel._plugins.get('coretasks')

    assert plugin is not None, 'coretasks should always be loaded'

    # Unregister the plugin
    plugin.unregister(sopel)
    # And now it must raise an exception
    with pytest.raises(plugins.exceptions.PluginNotRegistered):
        sopel.reload_plugin(plugin.name)
Beispiel #6
0
def test_search_url_callbacks_not_found(tmpconfig):
    """Test search_url_callbacks when pattern does not match."""
    sopel = bot.Sopel(tmpconfig, daemon=False)
    results = sopel.search_url_callbacks('https://example.com')
    assert not list(results), 'No handler registered; must return an empty list'

    def url_handler(*args, **kwargs):
        return None

    sopel.register_url_callback(r'https://(www\.)?example\.com', url_handler)

    results = sopel.search_url_callbacks('https://not-example.com')
    assert not list(results), 'URL must not match any pattern'
Beispiel #7
0
def test_register_unregister_plugin(tmpconfig, mockplugin):
    sopel = bot.Sopel(tmpconfig, daemon=False)

    # register the plugin
    mockplugin.load()
    mockplugin.register(sopel)
    assert sopel.has_plugin('mockplugin'), 'The mockplugin must be registered!'

    # unregister it
    mockplugin.unregister(sopel)
    assert not sopel.has_plugin('mockplugin')
    assert not sopel.rules.has_command('do')
    assert not sopel.rules.has_nick_command('info')
    assert not sopel.rules.has_action_command('tell')
Beispiel #8
0
def test_reload_plugin_unregistered_plugin(tmpconfig):
    sopel = bot.Sopel(tmpconfig, daemon=False)

    # register the plugin
    handler = plugins.handlers.PyModulePlugin('coretasks', 'sopel')
    handler.load()
    handler.register(sopel)

    # Unregister the plugin
    handler.unregister(sopel)

    # And now it must raise an exception
    with pytest.raises(plugins.exceptions.PluginNotRegistered):
        sopel.reload_plugin(handler.name)
Beispiel #9
0
def test_manual_url_callback_not_found(tmpconfig):
    """Test that the bot now ignores manually registered URL callbacks."""
    # Sopel 8.0 no longer supports `bot.memory['url_callbacks'], and this test
    # is to make sure that it *really* no longer works.
    test_pattern = r'https://(www\.)?example\.com'

    def url_handler(*args, **kwargs):
        return None

    sopel = bot.Sopel(tmpconfig, daemon=False)
    sopel.memory['url_callbacks'] = SopelMemory()

    # register a callback manually
    sopel.memory['url_callbacks'][re.compile(test_pattern)] = url_handler
    results = list(sopel.search_url_callbacks("https://www.example.com"))
    assert not results, "Manually registered callback must not be found"
Beispiel #10
0
def test_search_url_callbacks_compiled_pattern(tmpconfig):
    """Test search_url_callbacks for a registered compiled regex pattern."""
    sopel = bot.Sopel(tmpconfig, daemon=False)
    url_regex = re.compile(r'https://(www\.)?example\.com')

    def url_handler(*args, **kwargs):
        return None

    sopel.register_url_callback(url_regex, url_handler)
    results = list(sopel.search_url_callbacks('https://example.com'))
    assert len(results) == 1, 'Expected 1 handler; found %d' % len(results)
    assert url_handler in results[0], 'Once registered, handler must be found'

    results = list(sopel.search_url_callbacks('https://www.example.com'))
    assert len(results) == 1, 'Regex pattern must match both URLs'
    assert url_handler in results[0]
Beispiel #11
0
def test_register_plugin(tmpconfig, mockplugin):
    sopel = bot.Sopel(tmpconfig)
    assert not sopel.has_plugin('mockplugin')

    mockplugin.load()
    mockplugin.setup(sopel)
    mockplugin.register(sopel)

    assert sopel.has_plugin('mockplugin')
    assert sopel.rules.has_command('do')
    assert sopel.rules.has_command('do', plugin='mockplugin')
    assert sopel.rules.has_nick_command('info')
    assert sopel.rules.has_nick_command('info', plugin='mockplugin')
    assert sopel.rules.has_action_command('tell')
    assert sopel.rules.has_action_command('tell', plugin='mockplugin')
    assert list(sopel.search_url_callbacks('example.com'))
Beispiel #12
0
def test_register_unregister_plugin(tmpconfig):
    sopel = bot.Sopel(tmpconfig, daemon=False)

    # since `setup` hasn't been run, there is no registered plugin
    assert not sopel.has_plugin('coretasks')

    # register the plugin
    plugin = plugins.handlers.PyModulePlugin('coretasks', 'sopel')
    plugin.load()
    plugin.register(sopel)

    # and now there is!
    assert sopel.has_plugin('coretasks')

    # unregister it
    plugin.unregister(sopel)
    assert not sopel.has_plugin('coretasks')
Beispiel #13
0
def test_unregister_url_callback_compiled_pattern(tmpconfig):
    """Test unregister_url_callback works with a compiled regex."""
    test_pattern = r'https://(www\.)?example\.com'
    url_regex = re.compile(test_pattern)

    def url_handler(*args, **kwargs):
        return None

    sopel = bot.Sopel(tmpconfig, daemon=False)

    # now register a pattern, make sure it still work
    sopel.register_url_callback(test_pattern, url_handler)
    assert list(sopel.search_url_callbacks('https://www.example.com'))

    # unregister using the compiled version
    sopel.unregister_url_callback(url_regex, url_handler)

    assert not list(sopel.search_url_callbacks('https://www.example.com'))
Beispiel #14
0
def test_unregister_url_callback_unknown_pattern(tmpconfig):
    """Test unregister_url_callback pass when pattern is unknown."""
    test_pattern = r'https://(www\.)?example\.com'

    def url_handler(*args, **kwargs):
        return None

    sopel = bot.Sopel(tmpconfig, daemon=False)

    # now register a pattern, make sure it still work
    sopel.register_url_callback(test_pattern, url_handler)
    assert list(sopel.search_url_callbacks('https://www.example.com'))

    # unregister another pattern (that doesn't exist)
    sopel.unregister_url_callback(r'http://localhost', url_handler)

    # the existing pattern still work
    assert list(sopel.search_url_callbacks('https://www.example.com'))
Beispiel #15
0
def mockbot(configfactory):
    tmpconfig = configfactory('test.cfg', TMP_CONFIG)
    url_plugin = plugins.handlers.PyModulePlugin('url', 'sopel.modules')

    # setup the bot
    sopel = bot.Sopel(tmpconfig)
    url_plugin.load()
    url_plugin.setup(sopel)
    url_plugin.register(sopel)

    @plugin.url(re.escape('https://example.com/') + r'(.+)')
    @plugin.label('handle_urls_https')
    def url_callback_https(bot, trigger, match):
        pass

    @plugin.url(re.escape('http://example.com/') + r'(.+)')
    @plugin.label('handle_urls_http')
    def url_callback_http(bot, trigger, match):
        pass

    # prepare callables to be registered
    callables = [
        url_callback_https,
        url_callback_http,
    ]

    # clean callables and set plugin name by hand
    # since the loader and plugin handlers are excluded here
    for handler in callables:
        loader.clean_callable(handler, tmpconfig)
        handler.plugin_name = 'testplugin'

    # register callables
    sopel.register_urls(callables)

    # manually register URL Callback
    pattern = re.escape('https://help.example.com/') + r'(.+)'

    def callback(bot, trigger, match):
        pass

    sopel.register_url_callback(pattern, callback)
    return sopel
Beispiel #16
0
def test_unregister_url_callback(tmpconfig):
    """Test unregister_url_callback removes URL callback for a pattern."""
    test_pattern = r'https://(www\.)?example\.com'

    def url_handler(*args, **kwargs):
        return None

    sopel = bot.Sopel(tmpconfig, daemon=False)

    # now register a pattern, make sure it still work
    sopel.register_url_callback(test_pattern, url_handler)
    assert list(sopel.search_url_callbacks('https://www.example.com'))

    # unregister this pattern
    sopel.unregister_url_callback(test_pattern, url_handler)

    # now it is not possible to find a callback for this pattern
    results = list(sopel.search_url_callbacks('https://www.example.com'))
    assert not results, 'Unregistered URL callback must not work anymore'
Beispiel #17
0
def test_register_urls(tmpconfig):
    sopel = bot.Sopel(tmpconfig)

    @module.url(r'https://(\S+)/(.+)?')
    @plugin.label('handle_urls_https')
    def url_callback_https(bot, trigger, match):
        pass

    @module.url(r'http://(\S+)/(.+)?')
    @plugin.label('handle_urls_http')
    def url_callback_http(bot, trigger, match):
        pass

    # prepare callables to be registered
    callables = [
        url_callback_https,
        url_callback_http,
    ]

    # clean callables and set plugin name by hand
    # since the loader and plugin handlers are excluded here
    for handler in callables:
        loader.clean_callable(handler, tmpconfig)
        handler.plugin_name = 'testplugin'

    # register callables
    sopel.register_urls(callables)

    # trigger URL callback "handle_urls_https"
    line = ':[email protected] PRIVMSG #sopel :https://example.com/test'
    pretrigger = trigger.PreTrigger(sopel.nick, line)

    matches = sopel.rules.get_triggered_rules(sopel, pretrigger)
    assert len(matches) == 1
    assert matches[0][0].get_rule_label() == 'handle_urls_https'

    # trigger URL callback "handle_urls_https"
    line = ':[email protected] PRIVMSG #sopel :http://example.com/test'
    pretrigger = trigger.PreTrigger(sopel.nick, line)

    matches = sopel.rules.get_triggered_rules(sopel, pretrigger)
    assert len(matches) == 1
    assert matches[0][0].get_rule_label() == 'handle_urls_http'
Beispiel #18
0
def test_unregister_url_callback_manual(tmpconfig):
    """Test unregister_url_callback removes a specific callback that was added manually"""
    test_pattern = r'https://(www\.)?example\.com'

    def url_handler(*args, **kwargs):
        return None

    sopel = bot.Sopel(tmpconfig, daemon=False)
    sopel.memory["url_callbacks"] = SopelMemory()

    # register a callback manually
    sopel.memory["url_callbacks"][re.compile(test_pattern)] = url_handler
    results = list(sopel.search_url_callbacks("https://www.example.com"))
    assert results[0][0] == url_handler, "Callback must be present"

    # unregister it
    sopel.unregister_url_callback(test_pattern, url_handler)

    results = list(sopel.search_url_callbacks("https://www.example.com"))
    assert not results, "Callback should have been removed"
Beispiel #19
0
def test_register_url_callback_multiple(tmpconfig):
    """Test register_url_callback replace URL callbacks for a pattern."""
    test_pattern = r'https://(www\.)?example\.com'

    def url_handler(*args, **kwargs):
        return None

    def url_handler_replacement(*args, **kwargs):
        return None

    sopel = bot.Sopel(tmpconfig, daemon=False)
    sopel.register_url_callback(test_pattern, url_handler)

    results = list(sopel.search_url_callbacks('https://www.example.com'))
    assert url_handler in results[0]

    sopel.register_url_callback(test_pattern, url_handler_replacement)

    results = list(sopel.search_url_callbacks('https://www.example.com'))
    assert len(results) == 1, 'There must be one and only one callback'
    assert url_handler_replacement in results[0], (
        'Handler must have been replaced')
Beispiel #20
0
 def __call__(self, settings):
     obj = bot.Sopel(settings, daemon=False)
     obj.backend = MockIRCBackend(obj)
     return obj
Beispiel #21
0
def run(settings, pid_file, daemon=False):
    delay = 20

    if not settings.core.ca_certs:
        tools.stderr(
            'Could not open CA certificates file. SSL will not work properly!')

    def signal_handler(sig, frame):
        if sig == signal.SIGUSR1 or sig == signal.SIGTERM or sig == signal.SIGINT:
            tools.stderr('Got quit signal, shutting down.')
            p.quit('Closing')
        elif sig == signal.SIGUSR2 or sig == signal.SIGILL:
            tools.stderr('Got restart signal.')
            p.restart('Restarting')

    # Define empty variable `p` for bot
    p = None
    while True:
        if p and p.hasquit:  # Check if `hasquit` was set for bot during disconnected phase
            break
        try:
            p = bot.Sopel(settings, daemon=daemon)
            if hasattr(signal, 'SIGUSR1'):
                signal.signal(signal.SIGUSR1, signal_handler)
            if hasattr(signal, 'SIGTERM'):
                signal.signal(signal.SIGTERM, signal_handler)
            if hasattr(signal, 'SIGINT'):
                signal.signal(signal.SIGINT, signal_handler)
            if hasattr(signal, 'SIGUSR2'):
                signal.signal(signal.SIGUSR2, signal_handler)
            if hasattr(signal, 'SIGILL'):
                signal.signal(signal.SIGILL, signal_handler)
            p.setup()
            p.run(settings.core.host, int(settings.core.port))
        except KeyboardInterrupt:
            break
        except Exception:  # TODO: Be specific
            trace = traceback.format_exc()
            try:
                tools.stderr(trace)
            except Exception:  # TODO: Be specific
                pass
            logfile = open(os.path.join(settings.core.logdir, settings.basename + '.exceptions.log'), 'a')
            logfile.write('Critical exception in core')
            logfile.write(trace)
            logfile.write('----------------------------------------\n\n')
            logfile.close()
            # TODO: This should be handled by command_start
            # All we should need here is a return value, but replacing the
            # os._exit() call below (at the end) broke ^C.
            # This one is much harder to test, so until that one's sorted it
            # isn't worth the risk of trying to remove this one.
            os.unlink(pid_file)
            os._exit(1)

        if not isinstance(delay, int):
            break
        if p.wantsrestart:
            return -1
        if p.hasquit:
            break
        tools.stderr(
            'Warning: Disconnected. Reconnecting in %s seconds...' % delay)
        time.sleep(delay)
    # TODO: This should be handled by command_start
    # All we should need here is a return value, but making this
    # a return makes Sopel hang on ^C after it says "Closed!"
    os.unlink(pid_file)
    os._exit(0)
Beispiel #22
0
def test_register_callables(tmpconfig):
    sopel = bot.Sopel(tmpconfig)

    @module.rule(r'(hi|hello|hey|sup)')
    def rule_hello(bot, trigger):
        pass

    @plugin.find(r'(hi|hello|hey|sup)')
    def rule_find_hello(bot, trigger):
        pass

    @plugin.search(r'(hi|hello|hey|sup)')
    def rule_search_hello(bot, trigger):
        pass

    @module.commands('do')
    @module.example('.do nothing')
    def command_do(bot, trigger):
        """The do command does nothing."""
        pass

    @module.commands('main sub')
    @module.example('.main sub')
    def command_main_sub(bot, trigger):
        """A command with subcommand sub."""
        pass

    @module.commands('main other')
    @module.example('.main other')
    def command_main_other(bot, trigger):
        """A command with subcommand other."""
        pass

    @module.nickname_commands('info')
    @module.example('$nickname: info about this')
    def nick_command_info(bot, trigger):
        """Ask Sopel to get some info about nothing."""
        pass

    @module.action_commands('tell')
    def action_command_tell(bot, trigger):
        pass

    @module.commands('mixed')
    @module.rule('mixing')
    def mixed_rule_command(bot, trigger):
        pass

    @module.event('JOIN')
    @plugin.label('handle_join_event')
    def on_join(bot, trigger):
        pass

    # prepare callables to be registered
    callables = [
        rule_hello,
        rule_find_hello,
        rule_search_hello,
        command_do,
        command_main_sub,
        command_main_other,
        nick_command_info,
        action_command_tell,
        mixed_rule_command,
        on_join,
    ]

    # clean callables and set plugin name by hand
    # since the loader and plugin handlers are excluded here
    for handler in callables:
        loader.clean_callable(handler, tmpconfig)
        handler.plugin_name = 'testplugin'

    # register callables
    sopel.register_callables(callables)

    # trigger rule "hello"
    line = ':[email protected] PRIVMSG #sopel :hello'
    pretrigger = trigger.PreTrigger(sopel.nick, line)

    matches = sopel.rules.get_triggered_rules(sopel, pretrigger)
    assert len(matches) == 3
    assert matches[0][0].get_rule_label() == 'rule_hello'
    assert matches[1][0].get_rule_label() == 'rule_find_hello'
    assert matches[2][0].get_rule_label() == 'rule_search_hello'

    # trigger command "do"
    line = ':[email protected] PRIVMSG #sopel :.do'
    pretrigger = trigger.PreTrigger(sopel.nick, line)

    matches = sopel.rules.get_triggered_rules(sopel, pretrigger)
    assert len(matches) == 1
    assert matches[0][0].get_rule_label() == 'do'

    # trigger command with subcommand "main-sub"
    line = ':[email protected] PRIVMSG #sopel :.main sub'
    pretrigger = trigger.PreTrigger(sopel.nick, line)

    matches = sopel.rules.get_triggered_rules(sopel, pretrigger)
    assert len(matches) == 1
    assert matches[0][0].get_rule_label() == 'main-sub'

    # trigger command with the other subcommand "main-other"
    line = ':[email protected] PRIVMSG #sopel :.main other'
    pretrigger = trigger.PreTrigger(sopel.nick, line)

    matches = sopel.rules.get_triggered_rules(sopel, pretrigger)
    assert len(matches) == 1
    assert matches[0][0].get_rule_label() == 'main-other'

    # trigger nick command "info"
    line = ':[email protected] PRIVMSG #sopel :TestBot: info'
    pretrigger = trigger.PreTrigger(sopel.nick, line)

    matches = sopel.rules.get_triggered_rules(sopel, pretrigger)
    assert len(matches) == 1
    assert matches[0][0].get_rule_label() == 'info'

    # trigger action command "tell"
    line = ':[email protected] PRIVMSG #sopel :\x01ACTION tell\x01'
    pretrigger = trigger.PreTrigger(sopel.nick, line)

    matches = sopel.rules.get_triggered_rules(sopel, pretrigger)
    assert len(matches) == 1
    assert matches[0][0].get_rule_label() == 'tell'

    # trigger rules with event
    line = ':[email protected] JOIN #Sopel'
    pretrigger = trigger.PreTrigger(sopel.nick, line)

    matches = sopel.rules.get_triggered_rules(sopel, pretrigger)
    assert len(matches) == 1
    assert matches[0][0].get_rule_label() == 'handle_join_event'

    # trigger command "mixed"
    line = ':[email protected] PRIVMSG #sopel :.mixed'
    pretrigger = trigger.PreTrigger(sopel.nick, line)

    matches = sopel.rules.get_triggered_rules(sopel, pretrigger)
    assert len(matches) == 1
    assert matches[0][0].get_rule_label() == 'mixed'

    # trigger rule "mixed_rule_command"
    line = ':[email protected] PRIVMSG #sopel :mixing'
    pretrigger = trigger.PreTrigger(sopel.nick, line)

    matches = sopel.rules.get_triggered_rules(sopel, pretrigger)
    assert len(matches) == 1
    assert matches[0][0].get_rule_label() == 'mixed_rule_command'

    # check documentation
    assert sopel.command_groups == {
        'testplugin': ['do', 'info', 'main other', 'main sub', 'mixed'],
    }

    assert sopel.doc == {
        'do': (
            ['The do command does nothing.'],
            ['.do nothing'],
        ),
        'info': (
            ['Ask Sopel to get some info about nothing.'],
            ['TestBot: info about this'],
        ),
        'main sub': (
            ['A command with subcommand sub.'],
            ['.main sub'],
        ),
        'main other': (
            ['A command with subcommand other.'],
            ['.main other'],
        ),
        'mixed': (
            [],
            [],
        )
    }
Beispiel #23
0
def run(settings, pid_file, daemon=False):
    delay = 20

    # Acts as a welcome message, showing the program and platform version at start
    print_version()

    if not settings.core.ca_certs:
        tools.stderr(
            'Could not open CA certificates file. SSL will not work properly!')

    def signal_handler(sig, frame):
        if sig == signal.SIGUSR1 or sig == signal.SIGTERM or sig == signal.SIGINT:
            LOGGER.warning('Got quit signal, shutting down.')
            p.quit('Closing')
        elif sig == signal.SIGUSR2 or sig == signal.SIGILL:
            LOGGER.warning('Got restart signal, shutting down and restarting.')
            p.restart('Restarting')

    # Define empty variable `p` for bot
    p = None
    while True:
        if p and p.hasquit:  # Check if `hasquit` was set for bot during disconnected phase
            break
        try:
            p = bot.Sopel(settings, daemon=daemon)
            if hasattr(signal, 'SIGUSR1'):
                signal.signal(signal.SIGUSR1, signal_handler)
            if hasattr(signal, 'SIGTERM'):
                signal.signal(signal.SIGTERM, signal_handler)
            if hasattr(signal, 'SIGINT'):
                signal.signal(signal.SIGINT, signal_handler)
            if hasattr(signal, 'SIGUSR2'):
                signal.signal(signal.SIGUSR2, signal_handler)
            if hasattr(signal, 'SIGILL'):
                signal.signal(signal.SIGILL, signal_handler)
            p.setup()
        except KeyboardInterrupt:
            break
        except Exception:
            # In that case, there is nothing we can do.
            # If the bot can't setup itself, then it won't run.
            # This is a critical case scenario, where the user should have
            # direct access to the exception traceback right in the console.
            # Besides, we can't know if logging has been set up or not, so
            # we can't rely on that here.
            tools.stderr('Unexpected error in bot setup')
            raise

        try:
            p.run(settings.core.host, int(settings.core.port))
        except KeyboardInterrupt:
            break
        except Exception:
            err_log = logging.getLogger('sopel.exceptions')
            err_log.exception('Critical exception in core')
            err_log.error('----------------------------------------')
            # TODO: This should be handled by command_start
            # All we should need here is a return value, but replacing the
            # os._exit() call below (at the end) broke ^C.
            # This one is much harder to test, so until that one's sorted it
            # isn't worth the risk of trying to remove this one.
            os.unlink(pid_file)
            os._exit(1)

        if not isinstance(delay, int):
            break
        if p.wantsrestart:
            return -1
        if p.hasquit:
            break
        LOGGER.warning('Disconnected. Reconnecting in %s seconds...', delay)
        time.sleep(delay)
    # TODO: This should be handled by command_start
    # All we should need here is a return value, but making this
    # a return makes Sopel hang on ^C after it says "Closed!"
    os.unlink(pid_file)
    os._exit(0)
Beispiel #24
0
def test_remove_plugin_unknown_plugin(tmpconfig):
    sopel = bot.Sopel(tmpconfig, daemon=False)

    handler = plugins.handlers.PyModulePlugin('admin', 'sopel.modules')
    with pytest.raises(plugins.exceptions.PluginNotRegistered):
        sopel.remove_plugin(handler, [], [], [], [])
Beispiel #25
0
def run(settings, pid_file, daemon=False):
    """Run the bot with these ``settings``.

    :param settings: settings with which to run the bot
    :type settings: :class:`sopel.config.Config`
    :param str pid_file: path to the bot's PID file
    :param bool daemon: tell if the bot should be run as a daemon
    """
    delay = 20

    # Acts as a welcome message, showing the program and platform version at start
    print_version()
    # Also show the location of the config file used to load settings
    print("\nLoaded config file: {}".format(settings.filename))

    if not settings.core.ca_certs:
        tools.stderr(
            'Could not open CA certificates file. SSL will not work properly!')

    # Define empty variable `p` for bot
    p = None
    while True:
        if p and p.hasquit:  # Check if `hasquit` was set for bot during disconnected phase
            break
        try:
            p = bot.Sopel(settings, daemon=daemon)
            p.setup()
            p.set_signal_handlers()
        except KeyboardInterrupt:
            tools.stderr('Bot setup interrupted')
            break
        except Exception:
            # In that case, there is nothing we can do.
            # If the bot can't setup itself, then it won't run.
            # This is a critical case scenario, where the user should have
            # direct access to the exception traceback right in the console.
            # Besides, we can't know if logging has been set up or not, so
            # we can't rely on that here.
            tools.stderr('Unexpected error in bot setup')
            raise

        try:
            p.run(settings.core.host, int(settings.core.port))
        except KeyboardInterrupt:
            break
        except Exception:
            err_log = logging.getLogger('sopel.exceptions')
            err_log.exception('Critical exception in core')
            err_log.error('----------------------------------------')
            # TODO: This should be handled by command_start
            # All we should need here is a return value, but replacing the
            # os._exit() call below (at the end) broke ^C.
            # This one is much harder to test, so until that one's sorted it
            # isn't worth the risk of trying to remove this one.
            os.unlink(pid_file)
            os._exit(1)

        if not isinstance(delay, int):
            break
        if p.wantsrestart:
            return -1
        if p.hasquit:
            break
        LOGGER.warning('Disconnected. Reconnecting in %s seconds...', delay)
        time.sleep(delay)
    # TODO: This should be handled by command_start
    # All we should need here is a return value, but making this
    # a return makes Sopel hang on ^C after it says "Closed!"
    os.unlink(pid_file)
    os._exit(0)
Beispiel #26
0
def run(config, pid_file, daemon=False):
    import sopel.bot as bot
    import sopel.logger
    from sopel.tools import stderr
    delay = 20
    # Inject ca_certs from config to web for SSL validation of web requests
    if not config.core.ca_certs:
        stderr('Could not open CA certificates file. SSL will not '
               'work properly.')

    def signal_handler(sig, frame):
        if sig == signal.SIGUSR1 or sig == signal.SIGTERM or sig == signal.SIGINT:
            stderr('Got quit signal, shutting down.')
            p.quit('Closing')
        elif sig == signal.SIGUSR2 or sig == signal.SIGILL:
            stderr('Got restart signal.')
            p.restart('Restarting')

    while True:
        try:
            p = bot.Sopel(config, daemon=daemon)
            if hasattr(signal, 'SIGUSR1'):
                signal.signal(signal.SIGUSR1, signal_handler)
            if hasattr(signal, 'SIGTERM'):
                signal.signal(signal.SIGTERM, signal_handler)
            if hasattr(signal, 'SIGINT'):
                signal.signal(signal.SIGINT, signal_handler)
            if hasattr(signal, 'SIGUSR2'):
                signal.signal(signal.SIGUSR2, signal_handler)
            if hasattr(signal, 'SIGILL'):
                signal.signal(signal.SIGILL, signal_handler)
            sopel.logger.setup_logging(p)
            p.run(config.core.host, int(config.core.port))
        except KeyboardInterrupt:
            break
        except Exception:  # TODO: Be specific
            trace = traceback.format_exc()
            try:
                stderr(trace)
            except Exception:  # TODO: Be specific
                pass
            logfile = open(os.path.join(config.core.logdir, 'exceptions.log'),
                           'a')
            logfile.write('Critical exception in core')
            logfile.write(trace)
            logfile.write('----------------------------------------\n\n')
            logfile.close()
            # TODO: This should be handled in run_script
            # All we should need here is a return value, but replacing the
            # os._exit() call below (at the end) broke ^C.
            # This one is much harder to test, so until that one's sorted it
            # isn't worth the risk of trying to remove this one.
            os.unlink(pid_file)
            os._exit(1)

        if not isinstance(delay, int):
            break
        if p.wantsrestart:
            return -1
        if p.hasquit:
            break
        stderr('Warning: Disconnected. Reconnecting in %s seconds...' % delay)
        time.sleep(delay)
    # TODO: This should be handled in run_script
    # All we should need here is a return value, but making this
    # a return makes Sopel hang on ^C after it says "Closed!"
    os.unlink(pid_file)
    os._exit(0)
Beispiel #27
0
def mockbot(tmpconfig):
    obj = bot.Sopel(tmpconfig, daemon=False)
    obj.backend = MockIRCBackend(obj)
    return obj