PEP8 clean
This commit is contained in:
parent
95deafe7af
commit
e17996d858
23 changed files with 481 additions and 316 deletions
9
bot.py
9
bot.py
|
@ -36,11 +36,13 @@ from networkbot import NetworkBot
|
||||||
|
|
||||||
logger = logging.getLogger("nemubot.bot")
|
logger = logging.getLogger("nemubot.bot")
|
||||||
|
|
||||||
|
|
||||||
class Bot(threading.Thread):
|
class Bot(threading.Thread):
|
||||||
|
|
||||||
"""Class containing the bot context and ensuring key goals"""
|
"""Class containing the bot context and ensuring key goals"""
|
||||||
|
|
||||||
def __init__(self, ip="127.0.0.1", modules_paths=list(), data_path="./datas/"):
|
def __init__(self, ip="127.0.0.1", modules_paths=list(),
|
||||||
|
data_path="./datas/"):
|
||||||
"""Initialize the bot context
|
"""Initialize the bot context
|
||||||
|
|
||||||
Keyword arguments:
|
Keyword arguments:
|
||||||
|
@ -71,6 +73,7 @@ class Bot(threading.Thread):
|
||||||
|
|
||||||
# Own hooks
|
# Own hooks
|
||||||
self.hooks = HooksManager()
|
self.hooks = HooksManager()
|
||||||
|
|
||||||
def in_ping(msg):
|
def in_ping(msg):
|
||||||
if re.match("^ *(m[' ]?entends?[ -]+tu|h?ear me|do you copy|ping)", msg.message, re.I) is not None:
|
if re.match("^ *(m[' ]?entends?[ -]+tu|h?ear me|do you copy|ping)", msg.message, re.I) is not None:
|
||||||
return msg.respond("pong")
|
return msg.respond("pong")
|
||||||
|
@ -477,9 +480,9 @@ def reload():
|
||||||
prompt.reload()
|
prompt.reload()
|
||||||
|
|
||||||
import server
|
import server
|
||||||
rl,wl,xl = server._rlist,server._wlist,server._xlist
|
rl, wl, xl = server._rlist, server._wlist, server._xlist
|
||||||
imp.reload(server)
|
imp.reload(server)
|
||||||
server._rlist,server._wlist,server._xlist = rl,wl,xl
|
server._rlist, server._wlist, server._xlist = rl, wl, xl
|
||||||
|
|
||||||
server.reload()
|
server.reload()
|
||||||
|
|
||||||
|
|
67
channel.py
67
channel.py
|
@ -18,8 +18,19 @@
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
|
||||||
class Channel:
|
class Channel:
|
||||||
|
|
||||||
|
"""A chat room"""
|
||||||
|
|
||||||
def __init__(self, name, password=None):
|
def __init__(self, name, password=None):
|
||||||
|
"""Initialize the channel
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
name -- the channel name
|
||||||
|
password -- the optional password use to join it
|
||||||
|
"""
|
||||||
|
|
||||||
self.name = name
|
self.name = name
|
||||||
self.password = password
|
self.password = password
|
||||||
self.people = dict()
|
self.people = dict()
|
||||||
|
@ -27,6 +38,13 @@ class Channel:
|
||||||
self.logger = logging.getLogger("nemubot.channel." + name)
|
self.logger = logging.getLogger("nemubot.channel." + name)
|
||||||
|
|
||||||
def treat(self, cmd, msg):
|
def treat(self, cmd, msg):
|
||||||
|
"""Treat a incoming IRC command
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
cmd -- the command
|
||||||
|
msg -- the whole message
|
||||||
|
"""
|
||||||
|
|
||||||
if cmd == "353":
|
if cmd == "353":
|
||||||
self.parse353(msg)
|
self.parse353(msg)
|
||||||
elif cmd == "332":
|
elif cmd == "332":
|
||||||
|
@ -42,18 +60,35 @@ class Channel:
|
||||||
elif cmd == "TOPIC":
|
elif cmd == "TOPIC":
|
||||||
self.topic = self.text
|
self.topic = self.text
|
||||||
|
|
||||||
def join(self, nick, level = 0):
|
def join(self, nick, level=0):
|
||||||
"""Someone join the channel"""
|
"""Someone join the channel
|
||||||
|
|
||||||
|
Argument:
|
||||||
|
nick -- nickname of the user joining the channel
|
||||||
|
level -- authorization level of the user
|
||||||
|
"""
|
||||||
|
|
||||||
self.logger.debug("%s join", nick)
|
self.logger.debug("%s join", nick)
|
||||||
self.people[nick] = level
|
self.people[nick] = level
|
||||||
|
|
||||||
def chtopic(self, newtopic):
|
def chtopic(self, newtopic):
|
||||||
"""Send command to change the topic"""
|
"""Send command to change the topic
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
newtopic -- the new topic of the channel
|
||||||
|
"""
|
||||||
|
|
||||||
self.srv.send_msg(self.name, newtopic, "TOPIC")
|
self.srv.send_msg(self.name, newtopic, "TOPIC")
|
||||||
self.topic = newtopic
|
self.topic = newtopic
|
||||||
|
|
||||||
def nick(self, oldnick, newnick):
|
def nick(self, oldnick, newnick):
|
||||||
"""Someone change his nick"""
|
"""Someone change his nick
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
oldnick -- the previous nick of the user
|
||||||
|
newnick -- the new nick of the user
|
||||||
|
"""
|
||||||
|
|
||||||
if oldnick in self.people:
|
if oldnick in self.people:
|
||||||
self.logger.debug("%s switch nick to %s on", oldnick, newnick)
|
self.logger.debug("%s switch nick to %s on", oldnick, newnick)
|
||||||
lvl = self.people[oldnick]
|
lvl = self.people[oldnick]
|
||||||
|
@ -61,12 +96,22 @@ class Channel:
|
||||||
self.people[newnick] = lvl
|
self.people[newnick] = lvl
|
||||||
|
|
||||||
def part(self, nick):
|
def part(self, nick):
|
||||||
"""Someone leave the channel"""
|
"""Someone leave the channel
|
||||||
|
|
||||||
|
Argument:
|
||||||
|
nick -- name of the user that leave
|
||||||
|
"""
|
||||||
|
|
||||||
if nick in self.people:
|
if nick in self.people:
|
||||||
self.logger.debug("%s has left", nick)
|
self.logger.debug("%s has left", nick)
|
||||||
del self.people[nick]
|
del self.people[nick]
|
||||||
|
|
||||||
def mode(self, msg):
|
def mode(self, msg):
|
||||||
|
"""Channel or user mode change
|
||||||
|
|
||||||
|
Argument:
|
||||||
|
msg -- the whole message
|
||||||
|
"""
|
||||||
if msg.text[0] == "-k":
|
if msg.text[0] == "-k":
|
||||||
self.password = ""
|
self.password = ""
|
||||||
elif msg.text[0] == "+k":
|
elif msg.text[0] == "+k":
|
||||||
|
@ -88,9 +133,21 @@ class Channel:
|
||||||
self.people[msg.nick] &= ~1
|
self.people[msg.nick] &= ~1
|
||||||
|
|
||||||
def parse332(self, msg):
|
def parse332(self, msg):
|
||||||
|
"""Parse RPL_TOPIC message
|
||||||
|
|
||||||
|
Argument:
|
||||||
|
msg -- the whole message
|
||||||
|
"""
|
||||||
|
|
||||||
self.topic = msg.text
|
self.topic = msg.text
|
||||||
|
|
||||||
def parse353(self, msg):
|
def parse353(self, msg):
|
||||||
|
"""Parse RPL_ENDOFWHO message
|
||||||
|
|
||||||
|
Argument:
|
||||||
|
msg -- the whole message
|
||||||
|
"""
|
||||||
|
|
||||||
for p in msg.text:
|
for p in msg.text:
|
||||||
p = p.decode()
|
p = p.decode()
|
||||||
if p[0] == "@":
|
if p[0] == "@":
|
||||||
|
|
12
consumer.py
12
consumer.py
|
@ -23,6 +23,7 @@ import threading
|
||||||
|
|
||||||
logger = logging.getLogger("nemubot.consumer")
|
logger = logging.getLogger("nemubot.consumer")
|
||||||
|
|
||||||
|
|
||||||
class MessageConsumer:
|
class MessageConsumer:
|
||||||
|
|
||||||
"""Store a message before treating"""
|
"""Store a message before treating"""
|
||||||
|
@ -77,7 +78,7 @@ class MessageConsumer:
|
||||||
new_msg.append(res)
|
new_msg.append(res)
|
||||||
msg = None
|
msg = None
|
||||||
break
|
break
|
||||||
elif res is None or res == False:
|
elif res is None or res is False:
|
||||||
msg = None
|
msg = None
|
||||||
break
|
break
|
||||||
if msg is not None:
|
if msg is not None:
|
||||||
|
@ -134,7 +135,7 @@ class MessageConsumer:
|
||||||
new_msg.append(res)
|
new_msg.append(res)
|
||||||
msg = None
|
msg = None
|
||||||
break
|
break
|
||||||
elif res is None or res == False:
|
elif res is None or res is False:
|
||||||
msg = None
|
msg = None
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
|
@ -160,7 +161,8 @@ class MessageConsumer:
|
||||||
if self.responses is not None and len(self.responses) > 0:
|
if self.responses is not None and len(self.responses) > 0:
|
||||||
self.post_treat(context.hooks)
|
self.post_treat(context.hooks)
|
||||||
except:
|
except:
|
||||||
logger.exception("Error occurred during the processing of the %s: %s", type(self.msgs[0]).__name__, self.msgs[0])
|
logger.exception("Error occurred during the processing of the %s: "
|
||||||
|
"%s", type(self.msgs[0]).__name__, self.msgs[0])
|
||||||
|
|
||||||
for res in self.responses:
|
for res in self.responses:
|
||||||
to_server = None
|
to_server = None
|
||||||
|
@ -180,6 +182,7 @@ class MessageConsumer:
|
||||||
# Sent the message only if treat_post authorize it
|
# Sent the message only if treat_post authorize it
|
||||||
to_server.send_response(res)
|
to_server.send_response(res)
|
||||||
|
|
||||||
|
|
||||||
class EventConsumer:
|
class EventConsumer:
|
||||||
"""Store a event before treating"""
|
"""Store a event before treating"""
|
||||||
def __init__(self, evt, timeout=20):
|
def __init__(self, evt, timeout=20):
|
||||||
|
@ -198,7 +201,8 @@ class EventConsumer:
|
||||||
context.add_event(self.evt, eid=self.evt.id)
|
context.add_event(self.evt, eid=self.evt.id)
|
||||||
|
|
||||||
# Or remove reference of this event
|
# Or remove reference of this event
|
||||||
elif hasattr(self.evt, "module_src") and self.evt.module_src is not None:
|
elif (hasattr(self.evt, "module_src") and
|
||||||
|
self.evt.module_src is not None):
|
||||||
self.evt.module_src.REGISTERED_EVENTS.remove(self.evt.id)
|
self.evt.module_src.REGISTERED_EVENTS.remove(self.evt.id)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
from message import TextMessage, DirectAsk
|
from message import TextMessage, DirectAsk
|
||||||
|
|
||||||
|
|
||||||
class IRCException(Exception):
|
class IRCException(Exception):
|
||||||
|
|
||||||
def __init__(self, message, personnal=True):
|
def __init__(self, message, personnal=True):
|
||||||
|
@ -27,6 +28,8 @@ class IRCException(Exception):
|
||||||
|
|
||||||
def fill_response(self, msg):
|
def fill_response(self, msg):
|
||||||
if self.personnal:
|
if self.personnal:
|
||||||
return DirectAsk(msg.frm, self.message, server=msg.server, to=msg.to_response)
|
return DirectAsk(msg.frm, self.message,
|
||||||
|
server=msg.server, to=msg.to_response)
|
||||||
else:
|
else:
|
||||||
return TextMessage(self.message, server=msg.server, to=msg.to_response)
|
return TextMessage(self.message,
|
||||||
|
server=msg.server, to=msg.to_response)
|
||||||
|
|
|
@ -20,6 +20,7 @@ import imp
|
||||||
|
|
||||||
from exception import IRCException
|
from exception import IRCException
|
||||||
|
|
||||||
|
|
||||||
def call_game(call, *args, **kargs):
|
def call_game(call, *args, **kargs):
|
||||||
"""TODO"""
|
"""TODO"""
|
||||||
l = list()
|
l = list()
|
||||||
|
@ -70,6 +71,7 @@ from hooks.messagehook import MessageHook
|
||||||
|
|
||||||
last_registered = []
|
last_registered = []
|
||||||
|
|
||||||
|
|
||||||
def hook(store, *args, **kargs):
|
def hook(store, *args, **kargs):
|
||||||
"""Function used as a decorator for module loading"""
|
"""Function used as a decorator for module loading"""
|
||||||
def sec(call):
|
def sec(call):
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
# 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/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
class HooksManager:
|
class HooksManager:
|
||||||
|
|
||||||
"""Class to manage hooks"""
|
"""Class to manage hooks"""
|
||||||
|
|
|
@ -22,6 +22,7 @@ from exception import IRCException
|
||||||
import hooks
|
import hooks
|
||||||
import message
|
import message
|
||||||
|
|
||||||
|
|
||||||
class MessageHook(hooks.AbstractHook):
|
class MessageHook(hooks.AbstractHook):
|
||||||
|
|
||||||
"""Class storing hook information, specialized for a generic Message"""
|
"""Class storing hook information, specialized for a generic Message"""
|
||||||
|
@ -52,9 +53,9 @@ class MessageHook(hooks.AbstractHook):
|
||||||
|
|
||||||
def is_matching(self, strcmp, receivers=list(), server=None):
|
def is_matching(self, strcmp, receivers=list(), server=None):
|
||||||
"""Test if the current hook correspond to the message"""
|
"""Test if the current hook correspond to the message"""
|
||||||
if (server is None or self.server is None or self.server == server
|
if ((server is None or self.server is None or self.server == server)
|
||||||
) and ((self.name is None or strcmp == self.name) and (
|
and ((self.name is None or strcmp == self.name) and (
|
||||||
self.regexp is None or re.match(self.regexp, strcmp))):
|
self.regexp is None or re.match(self.regexp, strcmp)))):
|
||||||
|
|
||||||
if receivers and self.channels:
|
if receivers and self.channels:
|
||||||
for receiver in receivers:
|
for receiver in receivers:
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
import imp
|
import imp
|
||||||
|
|
||||||
|
|
||||||
class AbstractMessage:
|
class AbstractMessage:
|
||||||
|
|
||||||
"""This class represents an abstract message"""
|
"""This class represents an abstract message"""
|
||||||
|
@ -37,10 +38,12 @@ class AbstractMessage:
|
||||||
self.server = server
|
self.server = server
|
||||||
self.date = datetime.now(timezone.utc) if date is None else date
|
self.date = datetime.now(timezone.utc) if date is None else date
|
||||||
self.to = to if to is not None else list()
|
self.to = to if to is not None else list()
|
||||||
self._to_response = to_response if to_response is None or isinstance(to_response, list) else [ to_response ]
|
self._to_response = (to_response if (to_response is None or
|
||||||
self.frm = frm # None allowed when it designate this bot
|
isinstance(to_response, list))
|
||||||
|
else [ to_response ])
|
||||||
|
self.frm = frm # None allowed when it designate this bot
|
||||||
|
|
||||||
self.frm_owner = False # Filled later, in consumer
|
self.frm_owner = False # Filled later, in consumer
|
||||||
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -129,7 +132,6 @@ class DirectAsk(TextMessage):
|
||||||
|
|
||||||
self.designated = designated
|
self.designated = designated
|
||||||
|
|
||||||
|
|
||||||
def respond(self, message):
|
def respond(self, message):
|
||||||
return DirectAsk(self.frm,
|
return DirectAsk(self.frm,
|
||||||
message,
|
message,
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
from message import TextMessage
|
from message import TextMessage
|
||||||
from message.visitor import AbstractVisitor
|
from message.visitor import AbstractVisitor
|
||||||
|
|
||||||
|
|
||||||
class IRC(AbstractVisitor):
|
class IRC(AbstractVisitor):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
import imp
|
import imp
|
||||||
|
|
||||||
|
|
||||||
def reload():
|
def reload():
|
||||||
import message.printer.IRC
|
import message.printer.IRC
|
||||||
imp.reload(message.printer.IRC)
|
imp.reload(message.printer.IRC)
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
# 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/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
class AbstractVisitor:
|
class AbstractVisitor:
|
||||||
|
|
||||||
def visit(self, obj):
|
def visit(self, obj):
|
||||||
|
|
10
nemubot.py
10
nemubot.py
|
@ -31,7 +31,8 @@ if __name__ == "__main__":
|
||||||
# Setup loggin interface
|
# Setup loggin interface
|
||||||
logger = logging.getLogger("nemubot")
|
logger = logging.getLogger("nemubot")
|
||||||
|
|
||||||
formatter = logging.Formatter('%(asctime)s %(name)s %(levelname)s %(message)s')
|
formatter = logging.Formatter(
|
||||||
|
'%(asctime)s %(name)s %(levelname)s %(message)s')
|
||||||
|
|
||||||
ch = logging.StreamHandler()
|
ch = logging.StreamHandler()
|
||||||
ch.setFormatter(formatter)
|
ch.setFormatter(formatter)
|
||||||
|
@ -52,7 +53,7 @@ if __name__ == "__main__":
|
||||||
# Register the hook for futur import
|
# Register the hook for futur import
|
||||||
sys.meta_path.append(importer.ModuleFinder(context, prmpt))
|
sys.meta_path.append(importer.ModuleFinder(context, prmpt))
|
||||||
|
|
||||||
#Add modules dir path
|
# Add modules dir path
|
||||||
if os.path.isdir("./modules/"):
|
if os.path.isdir("./modules/"):
|
||||||
context.add_modules_path(
|
context.add_modules_path(
|
||||||
os.path.realpath(os.path.abspath("./modules/")))
|
os.path.realpath(os.path.abspath("./modules/")))
|
||||||
|
@ -82,8 +83,9 @@ if __name__ == "__main__":
|
||||||
bot.__version__)
|
bot.__version__)
|
||||||
context.start()
|
context.start()
|
||||||
except:
|
except:
|
||||||
logger.exception("\033[1;31mUnable to reload the prompt due to errors.\033[0"
|
logger.exception("\033[1;31mUnable to reload the prompt due to "
|
||||||
"m Fix them before trying to reload the prompt.")
|
"errors.\033[0m Fix them before trying to reload "
|
||||||
|
"the prompt.")
|
||||||
|
|
||||||
context.quit()
|
context.quit()
|
||||||
print("\nWaiting for other threads shuts down...")
|
print("\nWaiting for other threads shuts down...")
|
||||||
|
|
|
@ -25,7 +25,9 @@ import traceback
|
||||||
|
|
||||||
from . import builtins
|
from . import builtins
|
||||||
|
|
||||||
|
|
||||||
class Prompt:
|
class Prompt:
|
||||||
|
|
||||||
def __init__(self, hc=dict(), hl=dict()):
|
def __init__(self, hc=dict(), hl=dict()):
|
||||||
self.selectedServer = None
|
self.selectedServer = None
|
||||||
|
|
||||||
|
@ -56,8 +58,8 @@ class Prompt:
|
||||||
return ret
|
return ret
|
||||||
except:
|
except:
|
||||||
exc_type, exc_value, exc_traceback = sys.exc_info()
|
exc_type, exc_value, exc_traceback = sys.exc_info()
|
||||||
sys.stderr.write (traceback.format_exception_only(
|
sys.stderr.write(traceback.format_exception_only(exc_type,
|
||||||
exc_type, exc_value)[0])
|
exc_value)[0])
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def exec_cmd(self, toks, context):
|
def exec_cmd(self, toks, context):
|
||||||
|
@ -65,7 +67,7 @@ class Prompt:
|
||||||
if toks[0] in builtins.CAPS:
|
if toks[0] in builtins.CAPS:
|
||||||
return builtins.CAPS[toks[0]](toks, context, self)
|
return builtins.CAPS[toks[0]](toks, context, self)
|
||||||
elif toks[0] in self.HOOKS_CAPS:
|
elif toks[0] in self.HOOKS_CAPS:
|
||||||
(f,d) = self.HOOKS_CAPS[toks[0]]
|
f, d = self.HOOKS_CAPS[toks[0]]
|
||||||
return f(d, toks, context, self)
|
return f(d, toks, context, self)
|
||||||
else:
|
else:
|
||||||
print("Unknown command: `%s'" % toks[0])
|
print("Unknown command: `%s'" % toks[0])
|
||||||
|
@ -90,7 +92,8 @@ class Prompt:
|
||||||
ret = self.exec_cmd(toks, context)
|
ret = self.exec_cmd(toks, context)
|
||||||
except:
|
except:
|
||||||
exc_type, exc_value, exc_traceback = sys.exc_info()
|
exc_type, exc_value, exc_traceback = sys.exc_info()
|
||||||
traceback.print_exception(exc_type, exc_value, exc_traceback)
|
traceback.print_exception(exc_type, exc_value,
|
||||||
|
exc_traceback)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print("")
|
print("")
|
||||||
except EOFError:
|
except EOFError:
|
||||||
|
@ -102,6 +105,7 @@ class Prompt:
|
||||||
def hotswap(prompt):
|
def hotswap(prompt):
|
||||||
return Prompt(prompt.HOOKS_CAPS, prompt.HOOKS_LIST)
|
return Prompt(prompt.HOOKS_CAPS, prompt.HOOKS_LIST)
|
||||||
|
|
||||||
|
|
||||||
def reload():
|
def reload():
|
||||||
import prompt.builtins
|
import prompt.builtins
|
||||||
imp.reload(prompt.builtins)
|
imp.reload(prompt.builtins)
|
||||||
|
|
|
@ -25,6 +25,13 @@ logger = logging.getLogger("nemubot.prompt.builtins")
|
||||||
from server.IRC import IRC as IRCServer
|
from server.IRC import IRC as IRCServer
|
||||||
import xmlparser
|
import xmlparser
|
||||||
|
|
||||||
|
|
||||||
|
def get_boolean(d, k):
|
||||||
|
return (k in d and
|
||||||
|
mod["autoload"].lower() != "false" and
|
||||||
|
mod["autoload"].lower() != "off")
|
||||||
|
|
||||||
|
|
||||||
def end(toks, context, prompt):
|
def end(toks, context, prompt):
|
||||||
"""Quit the prompt for reload or exit"""
|
"""Quit the prompt for reload or exit"""
|
||||||
if toks[0] == "refresh":
|
if toks[0] == "refresh":
|
||||||
|
@ -52,7 +59,7 @@ def liste(toks, context, prompt):
|
||||||
if len(context.modules) == 0:
|
if len(context.modules) == 0:
|
||||||
print (" > No module loaded")
|
print (" > No module loaded")
|
||||||
elif l in prompt.HOOKS_LIST:
|
elif l in prompt.HOOKS_LIST:
|
||||||
(f,d) = prompt.HOOKS_LIST[l]
|
f, d = prompt.HOOKS_LIST[l]
|
||||||
f(d, context, prompt)
|
f(d, context, prompt)
|
||||||
else:
|
else:
|
||||||
print (" Unknown list `%s'" % l)
|
print (" Unknown list `%s'" % l)
|
||||||
|
@ -65,8 +72,7 @@ def load_file(filename, context):
|
||||||
config = xmlparser.parse_file(filename)
|
config = xmlparser.parse_file(filename)
|
||||||
|
|
||||||
# This is a true nemubot configuration file, load it!
|
# This is a true nemubot configuration file, load it!
|
||||||
if (config.getName() == "botconfig"
|
if config.getName() == "nemubotconfig":
|
||||||
or config.getName() == "nemubotconfig"):
|
|
||||||
# Preset each server in this file
|
# Preset each server in this file
|
||||||
for server in config.getNodes("server"):
|
for server in config.getNodes("server"):
|
||||||
opts = {
|
opts = {
|
||||||
|
@ -78,7 +84,8 @@ def load_file(filename, context):
|
||||||
}
|
}
|
||||||
|
|
||||||
# Optional keyword arguments
|
# Optional keyword arguments
|
||||||
for optional_opt in [ "port", "username", "realname", "password", "encoding", "caps" ]:
|
for optional_opt in [ "port", "username", "realname",
|
||||||
|
"password", "encoding", "caps" ]:
|
||||||
if server.hasAttribute(optional_opt):
|
if server.hasAttribute(optional_opt):
|
||||||
opts[optional_opt] = server[optional_opt]
|
opts[optional_opt] = server[optional_opt]
|
||||||
elif optional_opt in config:
|
elif optional_opt in config:
|
||||||
|
@ -94,11 +101,14 @@ def load_file(filename, context):
|
||||||
if server.hasNode("channel"):
|
if server.hasNode("channel"):
|
||||||
opts["channels"] = list()
|
opts["channels"] = list()
|
||||||
for chn in server.getNodes("channel"):
|
for chn in server.getNodes("channel"):
|
||||||
opts["channels"].append((chn["name"], chn["password"]) if chn["password"] is not None else chn["name"])
|
opts["channels"].append((chn["name"], chn["password"])
|
||||||
|
if chn["password"] is not None
|
||||||
|
else chn["name"])
|
||||||
|
|
||||||
# Server/client capabilities
|
# Server/client capabilities
|
||||||
if "caps" in server or "caps" in config:
|
if "caps" in server or "caps" in config:
|
||||||
capsl = (server["caps"] if server.hasAttribute("caps") else config["caps"]).lower()
|
capsl = (server["caps"] if server.hasAttribute("caps")
|
||||||
|
else config["caps"]).lower()
|
||||||
if capsl == "no" or capsl == "off" or capsl == "false":
|
if capsl == "no" or capsl == "off" or capsl == "false":
|
||||||
opts["caps"] = None
|
opts["caps"] = None
|
||||||
else:
|
else:
|
||||||
|
@ -110,14 +120,14 @@ def load_file(filename, context):
|
||||||
if "protocol" not in server or server["protocol"] == "irc":
|
if "protocol" not in server or server["protocol"] == "irc":
|
||||||
srvcls = IRCServer
|
srvcls = IRCServer
|
||||||
else:
|
else:
|
||||||
raise Exception("Unhandled protocol '%s'" % server["protocol"])
|
raise Exception("Unhandled protocol '%s'" %
|
||||||
|
server["protocol"])
|
||||||
|
|
||||||
# Initialize the server
|
# Initialize the server
|
||||||
srv = srvcls(**opts)
|
srv = srvcls(**opts)
|
||||||
|
|
||||||
# Add the server in the context
|
# Add the server in the context
|
||||||
if context.add_server(srv,
|
if context.add_server(srv, get_boolean(server, "autoconnect")):
|
||||||
"autoconnect" in server and server["autoconnect"].lower() != "false"):
|
|
||||||
print("Server '%s' successfully added." % srv.id)
|
print("Server '%s' successfully added." % srv.id)
|
||||||
else:
|
else:
|
||||||
print("Can't add server '%s'." % srv.id)
|
print("Can't add server '%s'." % srv.id)
|
||||||
|
@ -125,7 +135,7 @@ def load_file(filename, context):
|
||||||
# Load module and their configuration
|
# Load module and their configuration
|
||||||
for mod in config.getNodes("module"):
|
for mod in config.getNodes("module"):
|
||||||
context.modules_configuration[mod["name"]] = mod
|
context.modules_configuration[mod["name"]] = mod
|
||||||
if not mod.hasAttribute("autoload") or (mod["autoload"].lower() != "false" and mod["autoload"].lower() != "off"):
|
if get_boolean(mod, "autoload"):
|
||||||
__import__(mod["name"])
|
__import__(mod["name"])
|
||||||
|
|
||||||
# Load files asked by the configuration file
|
# Load files asked by the configuration file
|
||||||
|
@ -155,8 +165,8 @@ def load(toks, context, prompt):
|
||||||
|
|
||||||
def select(toks, context, prompt):
|
def select(toks, context, prompt):
|
||||||
"""Select the current server"""
|
"""Select the current server"""
|
||||||
if (len(toks) == 2 and toks[1] != "None"
|
if (len(toks) == 2 and toks[1] != "None" and
|
||||||
and toks[1] != "nemubot" and toks[1] != "none"):
|
toks[1] != "nemubot" and toks[1] != "none"):
|
||||||
if toks[1] in context.servers:
|
if toks[1] in context.servers:
|
||||||
prompt.selectedServer = context.servers[toks[1]]
|
prompt.selectedServer = context.servers[toks[1]]
|
||||||
else:
|
else:
|
||||||
|
@ -197,15 +207,15 @@ def debug(toks, context, prompt):
|
||||||
print ("Not enough arguments. `debug' takes a module name.")
|
print ("Not enough arguments. `debug' takes a module name.")
|
||||||
|
|
||||||
|
|
||||||
#Register build-ins
|
# Register build-ins
|
||||||
CAPS = {
|
CAPS = {
|
||||||
'quit': end, #Disconnect all server and quit
|
'quit': end, # Disconnect all server and quit
|
||||||
'exit': end, #Alias for quit
|
'exit': end, # Alias for quit
|
||||||
'reset': end, #Reload the prompt
|
'reset': end, # Reload the prompt
|
||||||
'refresh': end, #Reload the prompt but save modules
|
'refresh': end, # Reload the prompt but save modules
|
||||||
'load': load, #Load a servers or module configuration file
|
'load': load, # Load a servers or module configuration file
|
||||||
'unload': unload, #Unload a module and remove it from the list
|
'unload': unload, # Unload a module and remove it from the list
|
||||||
'select': select, #Select a server
|
'select': select, # Select a server
|
||||||
'list': liste, #Show lists
|
'list': liste, # Show lists
|
||||||
'debug': debug, #Pass a module in debug mode
|
'debug': debug, # Pass a module in debug mode
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,11 @@ from message.printer.IRC import IRC as IRCPrinter
|
||||||
from server.socket import SocketServer
|
from server.socket import SocketServer
|
||||||
import tools
|
import tools
|
||||||
|
|
||||||
|
|
||||||
class IRC(SocketServer):
|
class IRC(SocketServer):
|
||||||
|
|
||||||
|
"""Concrete implementation of a connexion to an IRC server"""
|
||||||
|
|
||||||
def __init__(self, owner, nick="nemubot", host="localhost", port=6667,
|
def __init__(self, owner, nick="nemubot", host="localhost", port=6667,
|
||||||
ssl=False, username=None, password=None, realname="Nemubot",
|
ssl=False, username=None, password=None, realname="Nemubot",
|
||||||
encoding="utf-8", caps=None, channels=list(),
|
encoding="utf-8", caps=None, channels=list(),
|
||||||
|
@ -155,7 +158,8 @@ class IRC(SocketServer):
|
||||||
|
|
||||||
# Respond to JOIN
|
# Respond to JOIN
|
||||||
def _on_join(msg):
|
def _on_join(msg):
|
||||||
if len(msg.params) == 0: return
|
if len(msg.params) == 0:
|
||||||
|
return
|
||||||
|
|
||||||
for chname in msg.decode(msg.params[0]).split(","):
|
for chname in msg.decode(msg.params[0]).split(","):
|
||||||
# Register the channel
|
# Register the channel
|
||||||
|
@ -164,7 +168,8 @@ class IRC(SocketServer):
|
||||||
self.hookscmd["JOIN"] = _on_join
|
self.hookscmd["JOIN"] = _on_join
|
||||||
# Respond to PART
|
# Respond to PART
|
||||||
def _on_part(msg):
|
def _on_part(msg):
|
||||||
if len(msg.params) != 1 and len(msg.params) != 2: return
|
if len(msg.params) != 1 and len(msg.params) != 2:
|
||||||
|
return
|
||||||
|
|
||||||
for chname in msg.params[0].split(b","):
|
for chname in msg.params[0].split(b","):
|
||||||
if chname in self.channels:
|
if chname in self.channels:
|
||||||
|
@ -175,7 +180,8 @@ class IRC(SocketServer):
|
||||||
self.hookscmd["PART"] = _on_part
|
self.hookscmd["PART"] = _on_part
|
||||||
# Respond to 331/RPL_NOTOPIC,332/RPL_TOPIC,TOPIC
|
# Respond to 331/RPL_NOTOPIC,332/RPL_TOPIC,TOPIC
|
||||||
def _on_topic(msg):
|
def _on_topic(msg):
|
||||||
if len(msg.params) != 1 and len(msg.params) != 2: return
|
if len(msg.params) != 1 and len(msg.params) != 2:
|
||||||
|
return
|
||||||
if msg.params[0] in self.channels:
|
if msg.params[0] in self.channels:
|
||||||
if len(msg.params) == 1 or len(msg.params[1]) == 0:
|
if len(msg.params) == 1 or len(msg.params[1]) == 0:
|
||||||
self.channels[msg.params[0]].topic = None
|
self.channels[msg.params[0]].topic = None
|
||||||
|
@ -186,8 +192,10 @@ class IRC(SocketServer):
|
||||||
self.hookscmd["TOPIC"] = _on_topic
|
self.hookscmd["TOPIC"] = _on_topic
|
||||||
# Respond to 353/RPL_NAMREPLY
|
# Respond to 353/RPL_NAMREPLY
|
||||||
def _on_353(msg):
|
def _on_353(msg):
|
||||||
if len(msg.params) == 3: msg.params.pop(0) # 353: like RFC 1459
|
if len(msg.params) == 3:
|
||||||
if len(msg.params) != 2: return
|
msg.params.pop(0) # 353: like RFC 1459
|
||||||
|
if len(msg.params) != 2:
|
||||||
|
return
|
||||||
if msg.params[0] in self.channels:
|
if msg.params[0] in self.channels:
|
||||||
for nk in msg.decode(msg.params[1]).split(" "):
|
for nk in msg.decode(msg.params[1]).split(" "):
|
||||||
res = re.match("^(?P<level>[^a-zA-Z[\]\\`_^{|}])(?P<nickname>[a-zA-Z[\]\\`_^{|}][a-zA-Z0-9[\]\\`_^{|}-]*)$")
|
res = re.match("^(?P<level>[^a-zA-Z[\]\\`_^{|}])(?P<nickname>[a-zA-Z[\]\\`_^{|}][a-zA-Z0-9[\]\\`_^{|}-]*)$")
|
||||||
|
@ -196,7 +204,8 @@ class IRC(SocketServer):
|
||||||
|
|
||||||
# Respond to INVITE
|
# Respond to INVITE
|
||||||
def _on_invite(msg):
|
def _on_invite(msg):
|
||||||
if len(msg.params) != 2: return
|
if len(msg.params) != 2:
|
||||||
|
return
|
||||||
self.write("JOIN " + msg.decode(msg.params[1]))
|
self.write("JOIN " + msg.decode(msg.params[1]))
|
||||||
self.hookscmd["INVITE"] = _on_invite
|
self.hookscmd["INVITE"] = _on_invite
|
||||||
|
|
||||||
|
@ -209,7 +218,8 @@ class IRC(SocketServer):
|
||||||
|
|
||||||
# Handle CTCP requests
|
# Handle CTCP requests
|
||||||
def _on_ctcp(msg):
|
def _on_ctcp(msg):
|
||||||
if len(msg.params) != 2 or not msg.is_ctcp: return
|
if len(msg.params) != 2 or not msg.is_ctcp:
|
||||||
|
return
|
||||||
cmds = msg.decode(msg.params[1][1:len(msg.params[1])-1]).split(' ')
|
cmds = msg.decode(msg.params[1][1:len(msg.params[1])-1]).split(' ')
|
||||||
if cmds[0] in self.ctcp_capabilities:
|
if cmds[0] in self.ctcp_capabilities:
|
||||||
res = self.ctcp_capabilities[cmds[0]](msg, cmds)
|
res = self.ctcp_capabilities[cmds[0]](msg, cmds)
|
||||||
|
@ -353,9 +363,10 @@ class IRCMessage:
|
||||||
client -- export as a client-side string if true
|
client -- export as a client-side string if true
|
||||||
"""
|
"""
|
||||||
|
|
||||||
res = ";".join(["@%s=%s" % (k,v if not isinstance(v, datetime) else v.strftime("%Y-%m-%dT%H:%M:%S.%fZ")) for k, v in self.tags.items()])
|
res = ";".join(["@%s=%s" % (k, v if not isinstance(v, datetime) else v.strftime("%Y-%m-%dT%H:%M:%S.%fZ")) for k, v in self.tags.items()])
|
||||||
|
|
||||||
if not client: res += " :%s!%s@%s" % (self.nick, self.user, self.host)
|
if not client:
|
||||||
|
res += " :%s!%s@%s" % (self.nick, self.user, self.host)
|
||||||
|
|
||||||
res += " " + self.cmd
|
res += " " + self.cmd
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ _rlist = []
|
||||||
_wlist = []
|
_wlist = []
|
||||||
_xlist = []
|
_xlist = []
|
||||||
|
|
||||||
|
|
||||||
# Extends from IOBase in order to be compatible with select function
|
# Extends from IOBase in order to be compatible with select function
|
||||||
class AbstractServer(io.IOBase):
|
class AbstractServer(io.IOBase):
|
||||||
|
|
||||||
|
@ -62,7 +63,8 @@ class AbstractServer(io.IOBase):
|
||||||
|
|
||||||
|
|
||||||
def open(self):
|
def open(self):
|
||||||
"""Generic open function that register the server un _rlist in case of successful _open"""
|
"""Generic open function that register the server un _rlist in case
|
||||||
|
of successful _open"""
|
||||||
self.logger.info("Opening connection to %s", self.id)
|
self.logger.info("Opening connection to %s", self.id)
|
||||||
if not hasattr(self, "_open") or self._open():
|
if not hasattr(self, "_open") or self._open():
|
||||||
_rlist.append(self)
|
_rlist.append(self)
|
||||||
|
@ -70,7 +72,8 @@ class AbstractServer(io.IOBase):
|
||||||
|
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""Generic close function that register the server un _{r,w,x}list in case of successful _close"""
|
"""Generic close function that register the server un _{r,w,x}list in
|
||||||
|
case of successful _close"""
|
||||||
self.logger.info("Closing connection to %s", self.id)
|
self.logger.info("Closing connection to %s", self.id)
|
||||||
if not hasattr(self, "_close") or self._close():
|
if not hasattr(self, "_close") or self._close():
|
||||||
if self in _rlist:
|
if self in _rlist:
|
||||||
|
|
|
@ -21,8 +21,11 @@ import socket
|
||||||
|
|
||||||
from server import AbstractServer
|
from server import AbstractServer
|
||||||
|
|
||||||
|
|
||||||
class SocketServer(AbstractServer):
|
class SocketServer(AbstractServer):
|
||||||
|
|
||||||
|
"""Concrete implementation of a socket connexion (can be wrapped with TLS)"""
|
||||||
|
|
||||||
def __init__(self, host, port, ssl=False):
|
def __init__(self, host, port, ssl=False):
|
||||||
AbstractServer.__init__(self)
|
AbstractServer.__init__(self)
|
||||||
self.host = host
|
self.host = host
|
||||||
|
@ -55,12 +58,13 @@ class SocketServer(AbstractServer):
|
||||||
self.socket = ctx.wrap_socket(self.socket)
|
self.socket = ctx.wrap_socket(self.socket)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.socket.connect((self.host, self.port)) #Connect to server
|
self.socket.connect((self.host, self.port)) # Connect to server
|
||||||
self.logger.info("Connected to %s:%d", self.host, self.port)
|
self.logger.info("Connected to %s:%d", self.host, self.port)
|
||||||
except socket.error as e:
|
except socket.error as e:
|
||||||
self.socket = None
|
self.socket = None
|
||||||
self.logger.critical("Unable to connect to %s:%d: %s",
|
self.logger.critical("Unable to connect to %s:%d: %s",
|
||||||
self.host, self.port, os.strerror(e.errno))
|
self.host, self.port,
|
||||||
|
os.strerror(e.errno))
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
@ -81,7 +85,8 @@ class SocketServer(AbstractServer):
|
||||||
# Write
|
# Write
|
||||||
|
|
||||||
def _write(self, cnt):
|
def _write(self, cnt):
|
||||||
if not self.connected: return
|
if not self.connected:
|
||||||
|
return
|
||||||
|
|
||||||
self.socket.send(cnt)
|
self.socket.send(cnt)
|
||||||
|
|
||||||
|
@ -96,7 +101,8 @@ class SocketServer(AbstractServer):
|
||||||
# Read
|
# Read
|
||||||
|
|
||||||
def read(self):
|
def read(self):
|
||||||
if not self.connected: return
|
if not self.connected:
|
||||||
|
return
|
||||||
|
|
||||||
raw = self.socket.recv(1024)
|
raw = self.socket.recv(1024)
|
||||||
temp = (self.readbuffer + raw).split(b'\r\n')
|
temp = (self.readbuffer + raw).split(b'\r\n')
|
||||||
|
|
|
@ -18,14 +18,16 @@
|
||||||
|
|
||||||
import imp
|
import imp
|
||||||
|
|
||||||
|
|
||||||
def intToIP(n):
|
def intToIP(n):
|
||||||
ip = ""
|
ip = ""
|
||||||
for i in range(0,4):
|
for i in range(0, 4):
|
||||||
mod = n % 256
|
mod = n % 256
|
||||||
ip = "%d.%s" % (mod, ip)
|
ip = "%d.%s" % (mod, ip)
|
||||||
n = (n - mod) / 256
|
n = (n - mod) / 256
|
||||||
return ip[:len(ip) - 1]
|
return ip[:len(ip) - 1]
|
||||||
|
|
||||||
|
|
||||||
def ipToInt(ip):
|
def ipToInt(ip):
|
||||||
sum = 0
|
sum = 0
|
||||||
for b in ip.split("."):
|
for b in ip.split("."):
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
|
||||||
def countdown(delta, resolution=5):
|
def countdown(delta, resolution=5):
|
||||||
sec = delta.seconds
|
sec = delta.seconds
|
||||||
hours, remainder = divmod(sec, 3600)
|
hours, remainder = divmod(sec, 3600)
|
||||||
|
@ -31,7 +32,7 @@ def countdown(delta, resolution=5):
|
||||||
|
|
||||||
if resolution > 0 and (force or an > 0):
|
if resolution > 0 and (force or an > 0):
|
||||||
force = True
|
force = True
|
||||||
sentence += " %i an"%(an)
|
sentence += " %i an" % an
|
||||||
|
|
||||||
if an > 1:
|
if an > 1:
|
||||||
sentence += "s"
|
sentence += "s"
|
||||||
|
@ -42,7 +43,7 @@ def countdown(delta, resolution=5):
|
||||||
|
|
||||||
if resolution > 1 and (force or days > 0):
|
if resolution > 1 and (force or days > 0):
|
||||||
force = True
|
force = True
|
||||||
sentence += " %i jour"%(days)
|
sentence += " %i jour" % days
|
||||||
|
|
||||||
if days > 1:
|
if days > 1:
|
||||||
sentence += "s"
|
sentence += "s"
|
||||||
|
@ -53,7 +54,7 @@ def countdown(delta, resolution=5):
|
||||||
|
|
||||||
if resolution > 2 and (force or hours > 0):
|
if resolution > 2 and (force or hours > 0):
|
||||||
force = True
|
force = True
|
||||||
sentence += " %i heure"%(hours)
|
sentence += " %i heure" % hours
|
||||||
if hours > 1:
|
if hours > 1:
|
||||||
sentence += "s"
|
sentence += "s"
|
||||||
if resolution > 4:
|
if resolution > 4:
|
||||||
|
@ -63,7 +64,7 @@ def countdown(delta, resolution=5):
|
||||||
|
|
||||||
if resolution > 3 and (force or minutes > 0):
|
if resolution > 3 and (force or minutes > 0):
|
||||||
force = True
|
force = True
|
||||||
sentence += " %i minute"%(minutes)
|
sentence += " %i minute" % minutes
|
||||||
if minutes > 1:
|
if minutes > 1:
|
||||||
sentence += "s"
|
sentence += "s"
|
||||||
if resolution > 4:
|
if resolution > 4:
|
||||||
|
@ -71,20 +72,21 @@ def countdown(delta, resolution=5):
|
||||||
|
|
||||||
if resolution > 4 and (force or seconds > 0):
|
if resolution > 4 and (force or seconds > 0):
|
||||||
force = True
|
force = True
|
||||||
sentence += " %i seconde"%(seconds)
|
sentence += " %i seconde" % seconds
|
||||||
if seconds > 1:
|
if seconds > 1:
|
||||||
sentence += "s"
|
sentence += "s"
|
||||||
return sentence[1:]
|
return sentence[1:]
|
||||||
|
|
||||||
|
|
||||||
def countdown_format(date, msg_before, msg_after, tz=None):
|
def countdown_format(date, msg_before, msg_after, tz=None):
|
||||||
"""Replace in a text %s by a sentence incidated the remaining time before/after an event"""
|
"""Replace in a text %s by a sentence incidated the remaining time
|
||||||
if tz != None:
|
before/after an event"""
|
||||||
|
if tz is not None:
|
||||||
oldtz = os.environ['TZ']
|
oldtz = os.environ['TZ']
|
||||||
os.environ['TZ'] = tz
|
os.environ['TZ'] = tz
|
||||||
time.tzset()
|
time.tzset()
|
||||||
|
|
||||||
#Calculate time before the date
|
# Calculate time before the date
|
||||||
try:
|
try:
|
||||||
if datetime.now(timezone.utc) > date:
|
if datetime.now(timezone.utc) > date:
|
||||||
sentence_c = msg_after
|
sentence_c = msg_after
|
||||||
|
@ -100,8 +102,7 @@ def countdown_format(date, msg_before, msg_after, tz=None):
|
||||||
sentence_c = msg_before
|
sentence_c = msg_before
|
||||||
delta = date - datetime.now()
|
delta = date - datetime.now()
|
||||||
|
|
||||||
|
if tz is not None:
|
||||||
if tz != None:
|
|
||||||
os.environ['TZ'] = oldtz
|
os.environ['TZ'] = oldtz
|
||||||
|
|
||||||
return sentence_c % countdown(delta)
|
return sentence_c % countdown(delta)
|
||||||
|
|
|
@ -29,24 +29,37 @@ xtrdt = re.compile(r'''^.*? (?P<day>[0-9]{1,4}) .+?
|
||||||
(?:[^0-9]*[m\":][^0-9]*(?P<second>[0-9]{1,2}))?)?)?.*?
|
(?:[^0-9]*[m\":][^0-9]*(?P<second>[0-9]{1,2}))?)?)?.*?
|
||||||
$''', re.X)
|
$''', re.X)
|
||||||
|
|
||||||
|
|
||||||
def extractDate(msg):
|
def extractDate(msg):
|
||||||
"""Parse a message to extract a time and date"""
|
"""Parse a message to extract a time and date"""
|
||||||
result = xtrdt.match(msg.lower())
|
result = xtrdt.match(msg.lower())
|
||||||
if result is not None:
|
if result is not None:
|
||||||
day = result.group("day")
|
day = result.group("day")
|
||||||
month = result.group("month")
|
month = result.group("month")
|
||||||
if month == "janvier" or month == "january" or month == "januar": month = 1
|
if month == "janvier" or month == "january" or month == "januar":
|
||||||
elif month == "fevrier" or month == "février" or month == "february": month = 2
|
month = 1
|
||||||
elif month == "mars" or month == "march": month = 3
|
elif month == "fevrier" or month == "février" or month == "february":
|
||||||
elif month == "avril" or month == "april": month = 4
|
month = 2
|
||||||
elif month == "mai" or month == "may" or month == "maï": month = 5
|
elif month == "mars" or month == "march":
|
||||||
elif month == "juin" or month == "juni" or month == "junni": month = 6
|
month = 3
|
||||||
elif month == "juillet" or month == "jully" or month == "july": month = 7
|
elif month == "avril" or month == "april":
|
||||||
elif month == "aout" or month == "août" or month == "august": month = 8
|
month = 4
|
||||||
elif month == "september" or month == "septembre": month = 9
|
elif month == "mai" or month == "may" or month == "maï":
|
||||||
elif month == "october" or month == "october" or month == "oktober": month = 10
|
month = 5
|
||||||
elif month == "november" or month == "novembre": month = 11
|
elif month == "juin" or month == "juni" or month == "junni":
|
||||||
elif month == "december" or month == "decembre" or month == "décembre": month = 12
|
month = 6
|
||||||
|
elif month == "juillet" or month == "jully" or month == "july":
|
||||||
|
month = 7
|
||||||
|
elif month == "aout" or month == "août" or month == "august":
|
||||||
|
month = 8
|
||||||
|
elif month == "september" or month == "septembre":
|
||||||
|
month = 9
|
||||||
|
elif month == "october" or month == "october" or month == "oktober":
|
||||||
|
month = 10
|
||||||
|
elif month == "november" or month == "novembre":
|
||||||
|
month = 11
|
||||||
|
elif month == "december" or month == "decembre" or month == "décembre":
|
||||||
|
month = 12
|
||||||
|
|
||||||
year = result.group("year")
|
year = result.group("year")
|
||||||
|
|
||||||
|
@ -57,9 +70,12 @@ def extractDate(msg):
|
||||||
minute = result.group("minute")
|
minute = result.group("minute")
|
||||||
second = result.group("second")
|
second = result.group("second")
|
||||||
|
|
||||||
if year is None: year = date.today().year
|
if year is None:
|
||||||
if hour is None: hour = 0
|
year = date.today().year
|
||||||
if minute is None: minute = 0
|
if hour is None:
|
||||||
|
hour = 0
|
||||||
|
if minute is None:
|
||||||
|
minute = 0
|
||||||
if second is None:
|
if second is None:
|
||||||
second = 1
|
second = 1
|
||||||
else:
|
else:
|
||||||
|
@ -68,6 +84,7 @@ def extractDate(msg):
|
||||||
minute = int(minute) + 1
|
minute = int(minute) + 1
|
||||||
second = 0
|
second = 0
|
||||||
|
|
||||||
return datetime(int(year), int(month), int(day), int(hour), int(minute), int(second))
|
return datetime(int(year), int(month), int(day),
|
||||||
|
int(hour), int(minute), int(second))
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
33
tools/web.py
33
tools/web.py
|
@ -28,31 +28,39 @@ from urllib.request import urlopen
|
||||||
from exception import IRCException
|
from exception import IRCException
|
||||||
import xmlparser
|
import xmlparser
|
||||||
|
|
||||||
|
|
||||||
def isURL(url):
|
def isURL(url):
|
||||||
"""Return True if the URL can be parsed"""
|
"""Return True if the URL can be parsed"""
|
||||||
o = urlparse(url)
|
o = urlparse(url)
|
||||||
return o.scheme == "" and o.netloc == "" and o.path == ""
|
return o.scheme == "" and o.netloc == "" and o.path == ""
|
||||||
|
|
||||||
|
|
||||||
def getScheme(url):
|
def getScheme(url):
|
||||||
"""Return the protocol of a given URL"""
|
"""Return the protocol of a given URL"""
|
||||||
o = urlparse(url)
|
o = urlparse(url)
|
||||||
return o.scheme
|
return o.scheme
|
||||||
|
|
||||||
|
|
||||||
def getHost(url):
|
def getHost(url):
|
||||||
"""Return the domain of a given URL"""
|
"""Return the domain of a given URL"""
|
||||||
return urlparse(url).netloc
|
return urlparse(url).netloc
|
||||||
|
|
||||||
|
|
||||||
def getPort(url):
|
def getPort(url):
|
||||||
"""Return the port of a given URL"""
|
"""Return the port of a given URL"""
|
||||||
return urlparse(url).port
|
return urlparse(url).port
|
||||||
|
|
||||||
|
|
||||||
def getPath(url):
|
def getPath(url):
|
||||||
"""Return the page request of a given URL"""
|
"""Return the page request of a given URL"""
|
||||||
return urlparse(url).path
|
return urlparse(url).path
|
||||||
|
|
||||||
|
|
||||||
def getUser(url):
|
def getUser(url):
|
||||||
"""Return the page request of a given URL"""
|
"""Return the page request of a given URL"""
|
||||||
return urlparse(url).username
|
return urlparse(url).username
|
||||||
|
|
||||||
|
|
||||||
def getPassword(url):
|
def getPassword(url):
|
||||||
"""Return the page request of a given URL"""
|
"""Return the page request of a given URL"""
|
||||||
return urlparse(url).password
|
return urlparse(url).password
|
||||||
|
@ -67,16 +75,19 @@ def getURLContent(url, timeout=15):
|
||||||
o = urlparse("http://" + url)
|
o = urlparse("http://" + url)
|
||||||
|
|
||||||
if o.scheme == "http":
|
if o.scheme == "http":
|
||||||
conn = http.client.HTTPConnection(o.netloc, port=o.port, timeout=timeout)
|
conn = http.client.HTTPConnection(o.netloc, port=o.port,
|
||||||
|
timeout=timeout)
|
||||||
elif o.scheme == "https":
|
elif o.scheme == "https":
|
||||||
conn = http.client.HTTPSConnection(o.netloc, port=o.port, timeout=timeout)
|
conn = http.client.HTTPSConnection(o.netloc, port=o.port,
|
||||||
|
timeout=timeout)
|
||||||
elif o.scheme is None or o.scheme == "":
|
elif o.scheme is None or o.scheme == "":
|
||||||
conn = http.client.HTTPConnection(o.netloc, port=80, timeout=timeout)
|
conn = http.client.HTTPConnection(o.netloc, port=80, timeout=timeout)
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
try:
|
try:
|
||||||
if o.query != '':
|
if o.query != '':
|
||||||
conn.request("GET", o.path + "?" + o.query, None, {"User-agent": "Nemubot v3"})
|
conn.request("GET", o.path + "?" + o.query,
|
||||||
|
None, {"User-agent": "Nemubot v3"})
|
||||||
else:
|
else:
|
||||||
conn.request("GET", o.path, None, {"User-agent": "Nemubot v3"})
|
conn.request("GET", o.path, None, {"User-agent": "Nemubot v3"})
|
||||||
except socket.timeout:
|
except socket.timeout:
|
||||||
|
@ -115,10 +126,14 @@ def getURLContent(url, timeout=15):
|
||||||
|
|
||||||
if res.status == http.client.OK or res.status == http.client.SEE_OTHER:
|
if res.status == http.client.OK or res.status == http.client.SEE_OTHER:
|
||||||
return data.decode(charset)
|
return data.decode(charset)
|
||||||
elif (res.status == http.client.FOUND or res.status == http.client.MOVED_PERMANENTLY) and res.getheader("Location") != url:
|
elif ((res.status == http.client.FOUND or
|
||||||
|
res.status == http.client.MOVED_PERMANENTLY) and
|
||||||
|
res.getheader("Location") != url):
|
||||||
return getURLContent(res.getheader("Location"), timeout)
|
return getURLContent(res.getheader("Location"), timeout)
|
||||||
else:
|
else:
|
||||||
raise IRCException("A HTTP error occurs: %d - %s" % (res.status, http.client.responses[res.status]))
|
raise IRCException("A HTTP error occurs: %d - %s" %
|
||||||
|
(res.status, http.client.responses[res.status]))
|
||||||
|
|
||||||
|
|
||||||
def getXML(url, timeout=15):
|
def getXML(url, timeout=15):
|
||||||
"""Get content page and return XML parsed content"""
|
"""Get content page and return XML parsed content"""
|
||||||
|
@ -128,6 +143,7 @@ def getXML(url, timeout=15):
|
||||||
else:
|
else:
|
||||||
return xmlparser.parse_string(cnt.encode())
|
return xmlparser.parse_string(cnt.encode())
|
||||||
|
|
||||||
|
|
||||||
def getJSON(url, timeout=15):
|
def getJSON(url, timeout=15):
|
||||||
"""Get content page and return JSON content"""
|
"""Get content page and return JSON content"""
|
||||||
cnt = getURLContent(url, timeout)
|
cnt = getURLContent(url, timeout)
|
||||||
|
@ -136,6 +152,7 @@ def getJSON(url, timeout=15):
|
||||||
else:
|
else:
|
||||||
return json.loads(cnt.decode())
|
return json.loads(cnt.decode())
|
||||||
|
|
||||||
|
|
||||||
# Other utils
|
# Other utils
|
||||||
|
|
||||||
def htmlentitydecode(s):
|
def htmlentitydecode(s):
|
||||||
|
@ -143,7 +160,11 @@ def htmlentitydecode(s):
|
||||||
return re.sub('&(%s);' % '|'.join(name2codepoint),
|
return re.sub('&(%s);' % '|'.join(name2codepoint),
|
||||||
lambda m: chr(name2codepoint[m.group(1)]), s)
|
lambda m: chr(name2codepoint[m.group(1)]), s)
|
||||||
|
|
||||||
|
|
||||||
def striphtml(data):
|
def striphtml(data):
|
||||||
"""Remove HTML tags from text"""
|
"""Remove HTML tags from text"""
|
||||||
p = re.compile(r'<.*?>')
|
p = re.compile(r'<.*?>')
|
||||||
return htmlentitydecode(p.sub('', data).replace("(", "/(").replace(")", ")/").replace(""", "\""))
|
return htmlentitydecode(p.sub('', data)
|
||||||
|
.replace("(", "/(")
|
||||||
|
.replace(")", ")/")
|
||||||
|
.replace(""", "\""))
|
||||||
|
|
|
@ -25,56 +25,59 @@ from . import node as module_state
|
||||||
|
|
||||||
logger = logging.getLogger("nemubot.xmlparser")
|
logger = logging.getLogger("nemubot.xmlparser")
|
||||||
|
|
||||||
|
|
||||||
class ModuleStatesFile(xml.sax.ContentHandler):
|
class ModuleStatesFile(xml.sax.ContentHandler):
|
||||||
def startDocument(self):
|
def startDocument(self):
|
||||||
self.root = None
|
self.root = None
|
||||||
self.stack = list()
|
self.stack = list()
|
||||||
|
|
||||||
def startElement(self, name, attrs):
|
def startElement(self, name, attrs):
|
||||||
cur = module_state.ModuleState(name)
|
cur = module_state.ModuleState(name)
|
||||||
|
|
||||||
for name in attrs.keys():
|
for name in attrs.keys():
|
||||||
cur.setAttribute(name, attrs.getValue(name))
|
cur.setAttribute(name, attrs.getValue(name))
|
||||||
|
|
||||||
self.stack.append(cur)
|
self.stack.append(cur)
|
||||||
|
|
||||||
def characters(self, content):
|
def characters(self, content):
|
||||||
self.stack[len(self.stack)-1].content += content
|
self.stack[len(self.stack)-1].content += content
|
||||||
|
|
||||||
|
def endElement(self, name):
|
||||||
|
child = self.stack.pop()
|
||||||
|
size = len(self.stack)
|
||||||
|
if size > 0:
|
||||||
|
self.stack[size - 1].content = self.stack[size - 1].content.strip()
|
||||||
|
self.stack[size - 1].addChild(child)
|
||||||
|
else:
|
||||||
|
self.root = child
|
||||||
|
|
||||||
def endElement(self, name):
|
|
||||||
child = self.stack.pop()
|
|
||||||
size = len(self.stack)
|
|
||||||
if size > 0:
|
|
||||||
self.stack[size - 1].content = self.stack[size - 1].content.strip()
|
|
||||||
self.stack[size - 1].addChild(child)
|
|
||||||
else:
|
|
||||||
self.root = child
|
|
||||||
|
|
||||||
def parse_file(filename):
|
def parse_file(filename):
|
||||||
parser = xml.sax.make_parser()
|
parser = xml.sax.make_parser()
|
||||||
mod = ModuleStatesFile()
|
mod = ModuleStatesFile()
|
||||||
parser.setContentHandler(mod)
|
parser.setContentHandler(mod)
|
||||||
try:
|
try:
|
||||||
parser.parse(open(filename, "r"))
|
parser.parse(open(filename, "r"))
|
||||||
return mod.root
|
return mod.root
|
||||||
except IOError:
|
except IOError:
|
||||||
logger.exception("error occurs during XML parsing of %s", filename)
|
logger.exception("error occurs during XML parsing of %s", filename)
|
||||||
return module_state.ModuleState("nemubotstate")
|
return module_state.ModuleState("nemubotstate")
|
||||||
except:
|
except:
|
||||||
logger.exception("error occurs during XML parsing of %s", filename)
|
logger.exception("error occurs during XML parsing of %s", filename)
|
||||||
if mod.root is None:
|
if mod.root is None:
|
||||||
return module_state.ModuleState("nemubotstate")
|
return module_state.ModuleState("nemubotstate")
|
||||||
else:
|
else:
|
||||||
return mod.root
|
return mod.root
|
||||||
|
|
||||||
|
|
||||||
def parse_string(string):
|
def parse_string(string):
|
||||||
mod = ModuleStatesFile()
|
mod = ModuleStatesFile()
|
||||||
try:
|
try:
|
||||||
xml.sax.parseString(string, mod)
|
xml.sax.parseString(string, mod)
|
||||||
return mod.root
|
return mod.root
|
||||||
except:
|
except:
|
||||||
logger.exception("error occurs during XML parsing")
|
logger.exception("error occurs during XML parsing")
|
||||||
if mod.root is None:
|
if mod.root is None:
|
||||||
return module_state.ModuleState("nemubotstate")
|
return module_state.ModuleState("nemubotstate")
|
||||||
else:
|
else:
|
||||||
return mod.root
|
return mod.root
|
||||||
|
|
|
@ -9,197 +9,206 @@ import traceback
|
||||||
|
|
||||||
logger = logging.getLogger("nemubot.xmlparser.node")
|
logger = logging.getLogger("nemubot.xmlparser.node")
|
||||||
|
|
||||||
|
|
||||||
class ModuleState:
|
class ModuleState:
|
||||||
"""Tiny tree representation of an XML file"""
|
"""Tiny tree representation of an XML file"""
|
||||||
|
|
||||||
def __init__(self, name):
|
def __init__(self, name):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.content = ""
|
self.content = ""
|
||||||
self.attributes = dict()
|
self.attributes = dict()
|
||||||
self.childs = list()
|
self.childs = list()
|
||||||
self.index = dict()
|
self.index = dict()
|
||||||
self.index_fieldname = None
|
self.index_fieldname = None
|
||||||
self.index_tagname = None
|
self.index_tagname = None
|
||||||
|
|
||||||
def getName(self):
|
def getName(self):
|
||||||
"""Get the name of the current node"""
|
"""Get the name of the current node"""
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def display(self, level = 0):
|
def display(self, level = 0):
|
||||||
ret = ""
|
ret = ""
|
||||||
out = list()
|
out = list()
|
||||||
for k in self.attributes:
|
for k in self.attributes:
|
||||||
out.append("%s : %s" % (k, self.attributes[k]))
|
out.append("%s : %s" % (k, self.attributes[k]))
|
||||||
ret += "%s%s { %s } = '%s'\n" % (' ' * level, self.name, ' ; '.join(out), self.content)
|
ret += "%s%s { %s } = '%s'\n" % (' ' * level, self.name,
|
||||||
for c in self.childs:
|
' ; '.join(out), self.content)
|
||||||
ret += c.display(level + 2)
|
for c in self.childs:
|
||||||
return ret
|
ret += c.display(level + 2)
|
||||||
|
return ret
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.display()
|
return self.display()
|
||||||
|
|
||||||
def __getitem__(self, i):
|
def __getitem__(self, i):
|
||||||
"""Return the attribute asked"""
|
"""Return the attribute asked"""
|
||||||
return self.getAttribute(i)
|
return self.getAttribute(i)
|
||||||
|
|
||||||
def __setitem__(self, i, c):
|
def __setitem__(self, i, c):
|
||||||
"""Set the attribute"""
|
"""Set the attribute"""
|
||||||
return self.setAttribute(i, c)
|
return self.setAttribute(i, c)
|
||||||
|
|
||||||
def getAttribute(self, name):
|
def getAttribute(self, name):
|
||||||
"""Get the asked argument or return None if doesn't exist"""
|
"""Get the asked argument or return None if doesn't exist"""
|
||||||
if name in self.attributes:
|
if name in self.attributes:
|
||||||
return self.attributes[name]
|
return self.attributes[name]
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def getDate(self, name=None):
|
def getDate(self, name=None):
|
||||||
"""Get the asked argument and return it as a date"""
|
"""Get the asked argument and return it as a date"""
|
||||||
if name is None:
|
if name is None:
|
||||||
source = self.content
|
source = self.content
|
||||||
elif name in self.attributes.keys():
|
elif name in self.attributes.keys():
|
||||||
source = self.attributes[name]
|
source = self.attributes[name]
|
||||||
else:
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
if isinstance(source, datetime):
|
||||||
|
return source
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
return datetime.fromtimestamp(float(source), timezone.utc)
|
||||||
|
except ValueError:
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
return datetime.fromtimestamp(time.mktime(
|
||||||
|
time.strptime(source[:19], "%Y-%m-%d %H:%M:%S")),
|
||||||
|
timezone.utc)
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def getInt(self, name=None):
|
||||||
|
"""Get the asked argument and return it as an integer"""
|
||||||
|
if name is None:
|
||||||
|
source = self.content
|
||||||
|
elif name in self.attributes.keys():
|
||||||
|
source = self.attributes[name]
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return int(float(source))
|
||||||
|
|
||||||
|
def getBool(self, name=None):
|
||||||
|
"""Get the asked argument and return it as an integer"""
|
||||||
|
if name is None:
|
||||||
|
source = self.content
|
||||||
|
elif name in self.attributes.keys():
|
||||||
|
source = self.attributes[name]
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return (isinstance(source, bool) and source) or source == "True"
|
||||||
|
|
||||||
|
def tmpIndex(self, fieldname="name", tagname=None):
|
||||||
|
index = dict()
|
||||||
|
for child in self.childs:
|
||||||
|
if ((tagname is None or tagname == child.name) and
|
||||||
|
child.hasAttribute(fieldname)):
|
||||||
|
index[child[fieldname]] = child
|
||||||
|
return index
|
||||||
|
|
||||||
|
def setIndex(self, fieldname="name", tagname=None):
|
||||||
|
"""Defines an hash table to accelerate childs search.
|
||||||
|
You have just to define a common attribute"""
|
||||||
|
self.index = self.tmpIndex(fieldname, tagname)
|
||||||
|
self.index_fieldname = fieldname
|
||||||
|
self.index_tagname = tagname
|
||||||
|
|
||||||
|
def __contains__(self, i):
|
||||||
|
"""Return true if i is found in the index"""
|
||||||
|
if self.index:
|
||||||
|
return i in self.index
|
||||||
|
else:
|
||||||
|
return self.hasAttribute(i)
|
||||||
|
|
||||||
|
def hasAttribute(self, name):
|
||||||
|
"""DOM like method"""
|
||||||
|
return (name in self.attributes)
|
||||||
|
|
||||||
|
def setAttribute(self, name, value):
|
||||||
|
"""DOM like method"""
|
||||||
|
if (isinstance(value, datetime) or isinstance(value, str) or
|
||||||
|
isinstance(value, int) or isinstance(value, float)):
|
||||||
|
self.attributes[name] = value
|
||||||
|
else:
|
||||||
|
raise TypeError("attributes must be primary type "
|
||||||
|
"or datetime (here %s)" % type(value))
|
||||||
|
|
||||||
|
def getContent(self):
|
||||||
|
return self.content
|
||||||
|
|
||||||
|
def getChilds(self):
|
||||||
|
"""Return a full list of direct child of this node"""
|
||||||
|
return self.childs
|
||||||
|
|
||||||
|
def getNode(self, tagname):
|
||||||
|
"""Get a unique node (or the last one) with the given tagname"""
|
||||||
|
ret = None
|
||||||
|
for child in self.childs:
|
||||||
|
if tagname is None or tagname == child.name:
|
||||||
|
ret = child
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def getFirstNode(self, tagname):
|
||||||
|
"""Get a unique node (or the last one) with the given tagname"""
|
||||||
|
for child in self.childs:
|
||||||
|
if tagname is None or tagname == child.name:
|
||||||
|
return child
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if isinstance(source, datetime):
|
def getNodes(self, tagname):
|
||||||
return source
|
"""Get all direct childs that have the given tagname"""
|
||||||
else:
|
for child in self.childs:
|
||||||
try:
|
if tagname is None or tagname == child.name:
|
||||||
return datetime.fromtimestamp(float(source), timezone.utc)
|
yield child
|
||||||
except ValueError:
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
return datetime.fromtimestamp(time.mktime(
|
|
||||||
time.strptime(source[:19], "%Y-%m-%d %H:%M:%S")), timezone.utc)
|
|
||||||
except ImportError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def getInt(self, name=None):
|
def hasNode(self, tagname):
|
||||||
"""Get the asked argument and return it as an integer"""
|
"""Return True if at least one node with the given tagname exists"""
|
||||||
if name is None:
|
for child in self.childs:
|
||||||
source = self.content
|
if tagname is None or tagname == child.name:
|
||||||
elif name in self.attributes.keys():
|
return True
|
||||||
source = self.attributes[name]
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
return int(float(source))
|
|
||||||
|
|
||||||
def getBool(self, name=None):
|
|
||||||
"""Get the asked argument and return it as an integer"""
|
|
||||||
if name is None:
|
|
||||||
source = self.content
|
|
||||||
elif name in self.attributes.keys():
|
|
||||||
source = self.attributes[name]
|
|
||||||
else:
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return (isinstance(source, bool) and source) or source == "True"
|
def addChild(self, child):
|
||||||
|
"""Add a child to this node"""
|
||||||
|
self.childs.append(child)
|
||||||
|
if self.index_fieldname is not None:
|
||||||
|
self.setIndex(self.index_fieldname, self.index_tagname)
|
||||||
|
|
||||||
def tmpIndex(self, fieldname="name", tagname=None):
|
def delChild(self, child):
|
||||||
index = dict()
|
"""Remove the given child from this node"""
|
||||||
for child in self.childs:
|
self.childs.remove(child)
|
||||||
if (tagname is None or tagname == child.name) and child.hasAttribute(fieldname):
|
if self.index_fieldname is not None:
|
||||||
index[child[fieldname]] = child
|
self.setIndex(self.index_fieldname, self.index_tagname)
|
||||||
return index
|
|
||||||
|
|
||||||
def setIndex(self, fieldname="name", tagname=None):
|
def save_node(self, gen):
|
||||||
"""Defines an hash table to accelerate childs search. You have just to define a common attribute"""
|
"""Serialize this node as a XML node"""
|
||||||
self.index = self.tmpIndex(fieldname, tagname)
|
attribs = {}
|
||||||
self.index_fieldname = fieldname
|
for att in self.attributes.keys():
|
||||||
self.index_tagname = tagname
|
if att[0] != "_": # Don't save attribute starting by _
|
||||||
|
if isinstance(self.attributes[att], datetime):
|
||||||
|
attribs[att] = str(time.mktime(
|
||||||
|
self.attributes[att].timetuple()))
|
||||||
|
else:
|
||||||
|
attribs[att] = str(self.attributes[att])
|
||||||
|
attrs = xml.sax.xmlreader.AttributesImpl(attribs)
|
||||||
|
|
||||||
def __contains__(self, i):
|
try:
|
||||||
"""Return true if i is found in the index"""
|
gen.startElement(self.name, attrs)
|
||||||
if self.index:
|
|
||||||
return i in self.index
|
|
||||||
else:
|
|
||||||
return self.hasAttribute(i)
|
|
||||||
|
|
||||||
def hasAttribute(self, name):
|
for child in self.childs:
|
||||||
"""DOM like method"""
|
child.save_node(gen)
|
||||||
return (name in self.attributes)
|
|
||||||
|
|
||||||
def setAttribute(self, name, value):
|
gen.endElement(self.name)
|
||||||
"""DOM like method"""
|
except:
|
||||||
if isinstance(value, datetime) or isinstance(value, str) or isinstance(value, int) or isinstance(value, float):
|
logger.exception("Error occured when saving the following "
|
||||||
self.attributes[name] = value
|
"XML node: %s with %s", self.name, attrs)
|
||||||
else:
|
|
||||||
raise TypeError("attributes must be primary type or datetime (here %s)" % type(value))
|
|
||||||
|
|
||||||
def getContent(self):
|
def save(self, filename):
|
||||||
return self.content
|
"""Save the current node as root node in a XML file"""
|
||||||
|
with open(filename, "w") as f:
|
||||||
def getChilds(self):
|
gen = xml.sax.saxutils.XMLGenerator(f, "utf-8")
|
||||||
"""Return a full list of direct child of this node"""
|
gen.startDocument()
|
||||||
return self.childs
|
self.save_node(gen)
|
||||||
|
gen.endDocument()
|
||||||
def getNode(self, tagname):
|
|
||||||
"""Get a unique node (or the last one) with the given tagname"""
|
|
||||||
ret = None
|
|
||||||
for child in self.childs:
|
|
||||||
if tagname is None or tagname == child.name:
|
|
||||||
ret = child
|
|
||||||
return ret
|
|
||||||
|
|
||||||
def getFirstNode(self, tagname):
|
|
||||||
"""Get a unique node (or the last one) with the given tagname"""
|
|
||||||
for child in self.childs:
|
|
||||||
if tagname is None or tagname == child.name:
|
|
||||||
return child
|
|
||||||
return None
|
|
||||||
|
|
||||||
def getNodes(self, tagname):
|
|
||||||
"""Get all direct childs that have the given tagname"""
|
|
||||||
for child in self.childs:
|
|
||||||
if tagname is None or tagname == child.name:
|
|
||||||
yield child
|
|
||||||
|
|
||||||
def hasNode(self, tagname):
|
|
||||||
"""Return True if at least one node with the given tagname exists"""
|
|
||||||
for child in self.childs:
|
|
||||||
if tagname is None or tagname == child.name:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def addChild(self, child):
|
|
||||||
"""Add a child to this node"""
|
|
||||||
self.childs.append(child)
|
|
||||||
if self.index_fieldname is not None:
|
|
||||||
self.setIndex(self.index_fieldname, self.index_tagname)
|
|
||||||
|
|
||||||
def delChild(self, child):
|
|
||||||
"""Remove the given child from this node"""
|
|
||||||
self.childs.remove(child)
|
|
||||||
if self.index_fieldname is not None:
|
|
||||||
self.setIndex(self.index_fieldname, self.index_tagname)
|
|
||||||
|
|
||||||
def save_node(self, gen):
|
|
||||||
"""Serialize this node as a XML node"""
|
|
||||||
attribs = {}
|
|
||||||
for att in self.attributes.keys():
|
|
||||||
if att[0] != "_": # Don't save attribute starting by _
|
|
||||||
if isinstance(self.attributes[att], datetime):
|
|
||||||
attribs[att] = str(time.mktime(self.attributes[att].timetuple()))
|
|
||||||
else:
|
|
||||||
attribs[att] = str(self.attributes[att])
|
|
||||||
attrs = xml.sax.xmlreader.AttributesImpl(attribs)
|
|
||||||
|
|
||||||
try:
|
|
||||||
gen.startElement(self.name, attrs)
|
|
||||||
|
|
||||||
for child in self.childs:
|
|
||||||
child.save_node(gen)
|
|
||||||
|
|
||||||
gen.endElement(self.name)
|
|
||||||
except:
|
|
||||||
logger.exception("Error occured when saving the following XML node: %s with %s", self.name, attrs)
|
|
||||||
|
|
||||||
def save(self, filename):
|
|
||||||
"""Save the current node as root node in a XML file"""
|
|
||||||
with open(filename,"w") as f:
|
|
||||||
gen = xml.sax.saxutils.XMLGenerator(f, "utf-8")
|
|
||||||
gen.startDocument()
|
|
||||||
self.save_node(gen)
|
|
||||||
gen.endDocument()
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue