diff --git a/nemubot/__init__.py b/nemubot/__init__.py
index 193ad53..d0a2072 100644
--- a/nemubot/__init__.py
+++ b/nemubot/__init__.py
@@ -47,6 +47,11 @@ def reload():
import nemubot.channel
imp.reload(nemubot.channel)
+ import nemubot.config
+ imp.reload(nemubot.config)
+
+ nemubot.config.reload()
+
import nemubot.consumer
imp.reload(nemubot.consumer)
diff --git a/nemubot/bot.py b/nemubot/bot.py
index b3dfbc1..54acdee 100644
--- a/nemubot/bot.py
+++ b/nemubot/bot.py
@@ -225,11 +225,18 @@ class Bot(threading.Thread):
if not os.path.isfile(filename):
return self.import_module(filename)
- from nemubot.tools.config import config_nodes
+ from nemubot.channel import Channel
+ from nemubot import config
from nemubot.tools.xmlparser import XMLParser
try:
- p = XMLParser(config_nodes)
+ p = XMLParser({
+ "nemubotconfig": config.Nemubot,
+ "server": config.Server,
+ "channel": Channel,
+ "module": config.Module,
+ "include": config.Include,
+ })
config = p.parse_file(filename)
except:
logger.exception("Can't load `%s'; this is not a valid nemubot "
diff --git a/nemubot/config/__init__.py b/nemubot/config/__init__.py
new file mode 100644
index 0000000..497bd9e
--- /dev/null
+++ b/nemubot/config/__init__.py
@@ -0,0 +1,47 @@
+# Nemubot is a smart and modulable IM bot.
+# Copyright (C) 2012-2015 Mercier Pierre-Olivier
+#
+# 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
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+def get_boolean(s):
+ if isinstance(s, bool):
+ return s
+ else:
+ return (s and s != "0" and s.lower() != "false" and s.lower() != "off")
+
+from nemubot.config.include import Include
+from nemubot.config.module import Module
+from nemubot.config.nemubot import Nemubot
+from nemubot.config.server import Server
+
+def reload():
+ global Include, Module, Nemubot, Server
+
+ import imp
+
+ import nemubot.config.include
+ imp.reload(nemubot.config.include)
+ Include = nemubot.config.include.Include
+
+ import nemubot.config.module
+ imp.reload(nemubot.config.module)
+ Module = nemubot.config.module.Module
+
+ import nemubot.config.nemubot
+ imp.reload(nemubot.config.nemubot)
+ Nemubot = nemubot.config.nemubot.Nemubot
+
+ import nemubot.config.server
+ imp.reload(nemubot.config.server)
+ Server = nemubot.config.server.Server
diff --git a/nemubot/config/include.py b/nemubot/config/include.py
new file mode 100644
index 0000000..40bea9a
--- /dev/null
+++ b/nemubot/config/include.py
@@ -0,0 +1,20 @@
+# Nemubot is a smart and modulable IM bot.
+# Copyright (C) 2012-2015 Mercier Pierre-Olivier
+#
+# 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
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+class Include:
+
+ def __init__(self, path):
+ self.path = path
diff --git a/nemubot/config/module.py b/nemubot/config/module.py
new file mode 100644
index 0000000..670e97b
--- /dev/null
+++ b/nemubot/config/module.py
@@ -0,0 +1,26 @@
+# Nemubot is a smart and modulable IM bot.
+# Copyright (C) 2012-2015 Mercier Pierre-Olivier
+#
+# 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
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+from nemubot.config import get_boolean
+from nemubot.tools.xmlparser.genericnode import GenericNode
+
+
+class Module(GenericNode):
+
+ def __init__(self, name, autoload=True, **kwargs):
+ super().__init__(None, **kwargs)
+ self.name = name
+ self.autoload = get_boolean(autoload)
diff --git a/nemubot/config/nemubot.py b/nemubot/config/nemubot.py
new file mode 100644
index 0000000..a2548a4
--- /dev/null
+++ b/nemubot/config/nemubot.py
@@ -0,0 +1,46 @@
+# Nemubot is a smart and modulable IM bot.
+# Copyright (C) 2012-2015 Mercier Pierre-Olivier
+#
+# 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
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+from nemubot.config.include import Include
+from nemubot.config.module import Module
+from nemubot.config.server import Server
+
+
+class Nemubot:
+
+ def __init__(self, nick="nemubot", realname="nemubot", owner=None,
+ ip=None, ssl=False, caps=None, encoding="utf-8"):
+ self.nick = nick
+ self.realname = realname
+ self.owner = owner
+ self.ip = ip
+ self.caps = caps.split(" ") if caps is not None else []
+ self.encoding = encoding
+ self.servers = []
+ self.modules = []
+ self.includes = []
+
+
+ def addChild(self, name, child):
+ if name == "module" and isinstance(child, Module):
+ self.modules.append(child)
+ return True
+ elif name == "server" and isinstance(child, Server):
+ self.servers.append(child)
+ return True
+ elif name == "include" and isinstance(child, Include):
+ self.includes.append(child)
+ return True
diff --git a/nemubot/config/server.py b/nemubot/config/server.py
new file mode 100644
index 0000000..c856649
--- /dev/null
+++ b/nemubot/config/server.py
@@ -0,0 +1,45 @@
+# Nemubot is a smart and modulable IM bot.
+# Copyright (C) 2012-2015 Mercier Pierre-Olivier
+#
+# 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
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+from nemubot.channel import Channel
+
+
+class Server:
+
+ def __init__(self, uri="irc://nemubot@localhost/", autoconnect=True, caps=None, **kwargs):
+ self.uri = uri
+ self.autoconnect = autoconnect
+ self.caps = caps.split(" ") if caps is not None else []
+ self.args = kwargs
+ self.channels = []
+
+
+ def addChild(self, name, child):
+ if name == "channel" and isinstance(child, Channel):
+ self.channels.append(child)
+ return True
+
+
+ def server(self, parent):
+ from nemubot.server import factory
+
+ for a in ["nick", "owner", "realname", "encoding"]:
+ if a not in self.args:
+ self.args[a] = getattr(parent, a)
+
+ self.caps += parent.caps
+
+ return factory(self.uri, caps=self.caps, channels=self.channels, **self.args)
diff --git a/nemubot/tools/config.py b/nemubot/tools/config.py
deleted file mode 100644
index f1305a7..0000000
--- a/nemubot/tools/config.py
+++ /dev/null
@@ -1,159 +0,0 @@
-# Nemubot is a smart and modulable IM bot.
-# Copyright (C) 2012-2015 Mercier Pierre-Olivier
-#
-# 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
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see .
-
-def get_boolean(s):
- if isinstance(s, bool):
- return s
- else:
- return (s and s != "0" and s.lower() != "false" and s.lower() != "off")
-
-
-class GenericNode:
-
- def __init__(self, tag, **kwargs):
- self.tag = tag
- self.attrs = kwargs
- self.content = ""
- self.children = []
- self._cur = None
- self._deep_cur = 0
-
-
- def startElement(self, name, attrs):
- if self._cur is None:
- self._cur = GenericNode(name, **attrs)
- self._deep_cur = 0
- else:
- self._deep_cur += 1
- self._cur.startElement(name, attrs)
- return True
-
-
- def characters(self, content):
- if self._cur is None:
- self.content += content
- else:
- self._cur.characters(content)
-
-
- def endElement(self, name):
- if name is None:
- return
-
- if self._deep_cur:
- self._deep_cur -= 1
- self._cur.endElement(name)
- else:
- self.children.append(self._cur)
- self._cur = None
- return True
-
-
- def hasNode(self, nodename):
- return self.getNode(nodename) is not None
-
-
- def getNode(self, nodename):
- for c in self.children:
- if c is not None and c.tag == nodename:
- return c
- return None
-
-
- def __getitem__(self, item):
- return self.attrs[item]
-
- def __contains__(self, item):
- return item in self.attrs
-
-
-class NemubotConfig:
-
- def __init__(self, nick="nemubot", realname="nemubot", owner=None,
- ip=None, ssl=False, caps=None, encoding="utf-8"):
- self.nick = nick
- self.realname = realname
- self.owner = owner
- self.ip = ip
- self.caps = caps.split(" ") if caps is not None else []
- self.encoding = encoding
- self.servers = []
- self.modules = []
- self.includes = []
-
-
- def addChild(self, name, child):
- if name == "module" and isinstance(child, ModuleConfig):
- self.modules.append(child)
- return True
- elif name == "server" and isinstance(child, ServerConfig):
- self.servers.append(child)
- return True
- elif name == "include" and isinstance(child, IncludeConfig):
- self.includes.append(child)
- return True
-
-
-class ServerConfig:
-
- def __init__(self, uri="irc://nemubot@localhost/", autoconnect=True, caps=None, **kwargs):
- self.uri = uri
- self.autoconnect = autoconnect
- self.caps = caps.split(" ") if caps is not None else []
- self.args = kwargs
- self.channels = []
-
-
- def addChild(self, name, child):
- if name == "channel" and isinstance(child, Channel):
- self.channels.append(child)
- return True
-
-
- def server(self, parent):
- from nemubot.server import factory
-
- for a in ["nick", "owner", "realname", "encoding"]:
- if a not in self.args:
- self.args[a] = getattr(parent, a)
-
- self.caps += parent.caps
-
- return factory(self.uri, caps=self.caps, channels=self.channels, **self.args)
-
-
-class IncludeConfig:
-
- def __init__(self, path):
- self.path = path
-
-
-class ModuleConfig(GenericNode):
-
- def __init__(self, name, autoload=True, **kwargs):
- super(ModuleConfig, self).__init__(None, **kwargs)
- self.name = name
- self.autoload = get_boolean(autoload)
-
-from nemubot.channel import Channel
-
-config_nodes = {
- "nemubotconfig": NemubotConfig,
- "server": ServerConfig,
- "channel": Channel,
- "module": ModuleConfig,
- "include": IncludeConfig,
-}
diff --git a/nemubot/tools/xmlparser/genericnode.py b/nemubot/tools/xmlparser/genericnode.py
new file mode 100644
index 0000000..efbdda9
--- /dev/null
+++ b/nemubot/tools/xmlparser/genericnode.py
@@ -0,0 +1,73 @@
+# Nemubot is a smart and modulable IM bot.
+# Copyright (C) 2012-2015 Mercier Pierre-Olivier
+#
+# 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
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see .
+
+class GenericNode:
+
+ def __init__(self, tag, **kwargs):
+ self.tag = tag
+ self.attrs = kwargs
+ self.content = ""
+ self.children = []
+ self._cur = None
+ self._deep_cur = 0
+
+
+ def startElement(self, name, attrs):
+ if self._cur is None:
+ self._cur = GenericNode(name, **attrs)
+ self._deep_cur = 0
+ else:
+ self._deep_cur += 1
+ self._cur.startElement(name, attrs)
+ return True
+
+
+ def characters(self, content):
+ if self._cur is None:
+ self.content += content
+ else:
+ self._cur.characters(content)
+
+
+ def endElement(self, name):
+ if name is None:
+ return
+
+ if self._deep_cur:
+ self._deep_cur -= 1
+ self._cur.endElement(name)
+ else:
+ self.children.append(self._cur)
+ self._cur = None
+ return True
+
+
+ def hasNode(self, nodename):
+ return self.getNode(nodename) is not None
+
+
+ def getNode(self, nodename):
+ for c in self.children:
+ if c is not None and c.tag == nodename:
+ return c
+ return None
+
+
+ def __getitem__(self, item):
+ return self.attrs[item]
+
+ def __contains__(self, item):
+ return item in self.attrs