1
0
Fork 0

Standardize Bot class names

This commit is contained in:
nemunaire 2014-07-17 15:27:28 +02:00
parent f9970cba42
commit 26faed014f
5 changed files with 72 additions and 54 deletions

View File

@ -1,8 +1,8 @@
#!/usr/bin/python3
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Nemubot is a modulable IRC bot, built around XML configuration files.
# Copyright (C) 2012 Mercier Pierre-Olivier
# Nemubot is a smart and modulable IM bot.
# Copyright (C) 2012-2014 nemunaire
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
@ -22,14 +22,14 @@ import os
import imp
import traceback
from nemubot import Bot
import nemubot
from nemubot import prompt
from nemubot.prompt.builtins import load_file
from nemubot import importer
if __name__ == "__main__":
# Create bot context
context = Bot(0, "FIXME")
context = nemubot.Bot()
# Load the prompt
prmpt = prompt.Prompt()
@ -50,7 +50,7 @@ if __name__ == "__main__":
else:
load_file(arg, context)
print ("Nemubot v%s ready, my PID is %i!" % (context.version_txt,
print ("Nemubot v%s ready, my PID is %i!" % (nemubot.__version__,
os.getpid()))
while prmpt.run(context):
try:
@ -63,7 +63,7 @@ if __name__ == "__main__":
# Reload all other modules
bot.reload()
print ("\033[1;32mContext reloaded\033[0m, now in Nemubot %s" %
context.version_txt)
nemubot.__version__)
except:
print ("\033[1;31mUnable to reload the prompt due to errors.\033[0"
"m Fix them before trying to reload the prompt.")

View File

@ -16,12 +16,14 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from datetime import datetime
from datetime import timedelta
from datetime import datetime, timedelta
from ipaddress import ip_address
import logging
from queue import Queue
import threading
import time
import re
import uuid
__version__ = '4.0.dev0'
__author__ = 'nemunaire'
from nemubot import consumer
from nemubot import event
@ -31,28 +33,30 @@ from nemubot.IRCServer import IRCServer
from nemubot.DCC import DCC
from nemubot import response
ID_letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
class Bot:
def __init__(self, ip, realname, mp=list()):
# Bot general informations
self.version = 4.0
self.version_txt = '4.0.dev0'
# Save various informations
self.ip = ip
self.realname = realname
self.ctcp_capabilities = dict()
self.init_ctcp_capabilities()
"""Class containing the bot context and ensuring key goals"""
def __init__(self, ip="127.0.0.1", modules_paths=list(), data_path="./datas/"):
"""Initialize the bot context
Keyword arguments:
ip -- The external IP of the bot (default: 127.0.0.1)
modules_paths -- Paths to all directories where looking for module
data_path -- Path to directory where store bot context data
"""
# External IP for accessing this bot
self.ip = ip_address(ip)
# Context paths
self.modules_paths = modules_paths
self.data_path = data_path
# Keep global context: servers and modules
self.servers = dict()
self.modules = dict()
# Context paths
self.modules_path = mp
self.datas_path = './datas/'
# Events
self.events = list()
self.event_timer = None
@ -62,13 +66,16 @@ class Bot:
# Other known bots, making a bots network
self.network = dict()
self.hooks_cache = dict()
self._hooks_cache = dict()
# Messages to be treated
self.cnsr_queue = Queue()
self.cnsr_thrd = list()
self.cnsr_thrd_size = -1
# Stop the class thread
self.stop = False
self.hooks.add_hook("irc_hook",
hooks.Hook(self.treat_prvmsg, "PRIVMSG"),
self)
@ -80,13 +87,13 @@ class Bot:
self.ctcp_capabilities["CLIENTINFO"] = self._ctcp_clientinfo
self.ctcp_capabilities["DCC"] = self._ctcp_dcc
self.ctcp_capabilities["NEMUBOT"] = lambda srv, msg: _ctcp_response(
msg.sender, "NEMUBOT %f" % self.version)
msg.sender, "NEMUBOT %f" % __version__)
self.ctcp_capabilities["TIME"] = lambda srv, msg: _ctcp_response(
msg.sender, "TIME %s" % (datetime.now()))
self.ctcp_capabilities["USERINFO"] = lambda srv, msg: _ctcp_response(
msg.sender, "USERINFO %s" % self.realname)
self.ctcp_capabilities["VERSION"] = lambda srv, msg: _ctcp_response(
msg.sender, "VERSION nemubot v%s" % self.version_txt)
msg.sender, "VERSION nemubot v%s" % __version__)
def _ctcp_clientinfo(self, srv, msg):
"""Response to CLIENTINFO CTCP message"""
@ -104,6 +111,8 @@ class Bot:
print ("DCC: unable to connect to %s:%s" % (ip, msg.cmds[4]))
# Events methods
def add_event(self, evt, eid=None, module_src=None):
"""Register an event and return its identifiant for futur update"""
if eid is None:
@ -125,7 +134,7 @@ class Bot:
break
self.events.insert(i + 1, evt)
if i == -1:
self.update_timer()
self._update_event_timer()
if len(self.events) <= 0 or self.events[i+1] != evt:
return None
@ -138,7 +147,7 @@ class Bot:
"""Find and remove an event from list"""
if len(self.events) > 0 and id == self.events[0].id:
self.events.remove(self.events[0])
self.update_timer()
self._update_event_timer()
if module_src is not None:
module_src.REGISTERED_EVENTS.remove(evt.id)
return True
@ -152,7 +161,7 @@ class Bot:
return True
return False
def update_timer(self):
def _update_event_timer(self):
"""Relaunch the timer to end with the closest event"""
# Reset the timer if this is the first item
if self.event_timer is not None:
@ -180,9 +189,11 @@ class Bot:
self.cnsr_queue.put_nowait(consumer.EventConsumer(evt))
self.update_consumers()
self.update_timer()
self._update_event_timer()
# Server methods
def addServer(self, node, nick, owner, realname, ssl=False):
"""Add a new server to the context"""
srv = IRCServer(node, nick, owner, realname, ssl)
@ -199,6 +210,8 @@ class Bot:
return False
# Modules methods
def add_module(self, module):
"""Add a module to the context, if already exists, unload the
old one before"""
@ -218,8 +231,8 @@ class Bot:
if path[len(path)-1] != "/":
path = path + "/"
if path not in self.modules_path:
self.modules_path.append(path)
if path not in self.modules_paths:
self.modules_paths.append(path)
return True
return False
@ -243,6 +256,9 @@ class Bot:
return True
return False
# Consumers methods
def update_consumers(self):
"""Launch new consumer thread if necessary"""
if self.cnsr_queue.qsize() > self.cnsr_thrd_size:
@ -292,14 +308,14 @@ class Bot:
# Hooks cache
def create_cache(self, name):
if name not in self.hooks_cache:
if name not in self._hooks_cache:
if isinstance(self.hooks.__dict__[name], list):
self.hooks_cache[name] = list()
self._hooks_cache[name] = list()
# Start by adding locals hooks
for h in self.hooks.__dict__[name]:
tpl = (h, 0, self.hooks.__dict__[name], self.hooks.bot)
self.hooks_cache[name].append(tpl)
self._hooks_cache[name].append(tpl)
# Now, add extermal hooks
level = 0
@ -309,17 +325,17 @@ class Bot:
if len(self.network[ext].hooks) > level:
lvl_exist = True
for h in self.network[ext].hooks[level].__dict__[name]:
if h not in self.hooks_cache[name]:
self.hooks_cache[name].append((h, level + 1,
if h not in self._hooks_cache[name]:
self._hooks_cache[name].append((h, level + 1,
self.network[ext].hooks[level].__dict__[name], self.network[ext].hooks[level].bot))
level += 1
elif isinstance(self.hooks.__dict__[name], dict):
self.hooks_cache[name] = dict()
self._hooks_cache[name] = dict()
# Start by adding locals hooks
for h in self.hooks.__dict__[name]:
self.hooks_cache[name][h] = (self.hooks.__dict__[name][h], 0,
self._hooks_cache[name][h] = (self.hooks.__dict__[name][h], 0,
self.hooks.__dict__[name],
self.hooks.bot)
@ -331,14 +347,14 @@ class Bot:
if len(self.network[ext].hooks) > level:
lvl_exist = True
for h in self.network[ext].hooks[level].__dict__[name]:
if h not in self.hooks_cache[name]:
self.hooks_cache[name][h] = (self.network[ext].hooks[level].__dict__[name][h], level + 1, self.network[ext].hooks[level].__dict__[name], self.network[ext].hooks[level].bot)
if h not in self._hooks_cache[name]:
self._hooks_cache[name][h] = (self.network[ext].hooks[level].__dict__[name][h], level + 1, self.network[ext].hooks[level].__dict__[name], self.network[ext].hooks[level].bot)
level += 1
else:
raise Exception(name + " hook type unrecognized")
return self.hooks_cache[name]
return self._hooks_cache[name]
# Treatment
@ -603,7 +619,7 @@ def _help_msg(sndr, modules, cmd):
return res
def hotswap(bak):
return Bot(bak.servers, bak.modules, bak.modules_path)
return Bot(bak.servers, bak.modules, bak.modules_paths)
def reload():
import imp

View File

@ -56,8 +56,8 @@ class MessagesHook:
"add_hook function, please fix it in order to be "
"compatible with unload feature")
if store in self.context.hooks_cache:
del self.context.hooks_cache[store]
if store in self.context._hooks_cache:
del self.context._hooks_cache[store]
if not hasattr(self, store):
print ("\033[1;35mWarning:\033[0m unrecognized hook store")
@ -143,8 +143,8 @@ class MessagesHook:
def del_hook(self, store, hook, module_src=None):
"""Remove a registered hook from a given store"""
if store in self.context.hooks_cache:
del self.context.hooks_cache[store]
if store in self.context._hooks_cache:
del self.context._hooks_cache[store]
if not hasattr(self, store):
print ("Warning: unrecognized hook store type")

View File

@ -16,12 +16,14 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from distutils.version import StrictVersion
from importlib.abc import Finder
from importlib.abc import SourceLoader
import imp
import os
import sys
import nemubot
from nemubot import event
from nemubot import exception
from nemubot.hooks import Hook
@ -37,7 +39,7 @@ class ModuleFinder(Finder):
#print ("looking for", fullname, "in", path)
# Search only for new nemubot modules (packages init)
if path is None:
for mpath in self.context.modules_path:
for mpath in self.context.modules_paths:
#print ("looking for", fullname, "in", mpath)
if os.path.isfile(mpath + fullname + ".xml"):
return ModuleLoader(self.context, self.prompt, fullname,
@ -137,7 +139,7 @@ class ModuleLoader(SourceLoader):
if not hasattr(module, "nemubotversion"):
raise ImportError("Module `%s' is not a nemubot module."%self.name)
# Check module version
if module.nemubotversion != self.context.version:
if StrictVersion(module.nemubotversion) != StrictVersion(nemubot.__version__):
raise ImportError("Module `%s' is not compatible with this "
"version." % self.name)

View File

@ -12,7 +12,7 @@ except ImportError:
with open(os.path.join(os.path.dirname(__file__),
'lib',
'__init__.py')) as f:
version = re.search("self.version_txt = '([^']+)'", f.read()).group(1)
version = re.search("__version__ = '([^']+)'", f.read()).group(1)
with open('requirements.txt', 'r') as f:
requires = [x.strip() for x in f if x.strip()]