From 7ff54100bb0ea9c65f64ca46bf30ef251e7e5345 Mon Sep 17 00:00:00 2001 From: "louiz@4325f9fc-e183-4c21-96ce-0ab188b42d13" Date: Tue, 18 May 2010 13:29:02 +0000 Subject: pylint cleaning part1 --- src/client.py | 40 +++----- src/common.py | 95 ++++++++++-------- src/config.py | 55 ++++++++--- src/connection.py | 76 +++++++++++--- src/gui.py | 290 +++++++++++++++++++++++++++++++++++++++++++----------- 5 files changed, 401 insertions(+), 155 deletions(-) diff --git a/src/client.py b/src/client.py index dfc31f3c..3e6d4fef 100644 --- a/src/client.py +++ b/src/client.py @@ -17,6 +17,10 @@ # You should have received a copy of the GNU General Public License # along with Poezio. If not, see . +""" +Starting point of poezio. Launches both the Connection and Gui +""" + import sys # disable any printout (this would mess the display) @@ -26,46 +30,26 @@ sys.stderr = open('errors', 'w') from connection import Connection from multiuserchat import MultiUserChat from config import config -from handler import Handler from gui import Gui from curses import initscr -import curses -import threading from common import exception_handler import signal -signal.signal(signal.SIGINT, signal.SIG_IGN) +signal.signal(signal.SIGINT, signal.SIG_IGN) # ignore ctrl-c sys.excepthook = exception_handler -class Client(object): - """ - Main class - Just read some configuration and instantiate the classes - """ - def __init__(self): - self.handler = Handler() - - self.resource = config.get('resource', 'poezio') - self.server = config.get('server', 'louiz.org') - self.connection = Connection(self.server, self.resource) - self.connection.start() - self.stdscr = initscr() - self.gui = Gui(self.stdscr, MultiUserChat(self.connection.client)) - - def launch(self): - """ - launch the gui - """ - self.gui.main_loop(self.stdscr) - def main(): """ main function """ - client = Client() - client.launch() - sys.exit() + resource = config.get('resource', 'poezio') + server = config.get('server', 'louiz.org') + connection = Connection(server, resource) + connection.start() + stdscr = initscr() + gui = Gui(stdscr, MultiUserChat(connection.client)) + gui.main_loop(stdscr) if __name__ == '__main__': main() diff --git a/src/common.py b/src/common.py index 1c119c1e..1dabcc06 100644 --- a/src/common.py +++ b/src/common.py @@ -30,7 +30,9 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -__doc__ = "various useful functions" +""" +various useful functions +""" import base64 import os @@ -40,11 +42,18 @@ import subprocess import curses import traceback import sys +import select +import errno -def debug(s): - f = open("debug", 'a') - f.write(s+'\n') - f.close() +def debug(string): + """ + Print a string in a file. + Useful since debuging cannot be displayed on screen because it's + a CLI software + """ + fdes = open("debug", 'a') + fdes.write(string+'\n') + fdes.close() def exception_handler(type_, value, trace): """ @@ -57,19 +66,25 @@ def exception_handler(type_, value, trace): sys.exit(2) def get_base64_from_file(path): + """ + Convert the content of a file to base64 + """ if not os.path.isfile(path): return (None, None, "File does not exist") size = os.path.getsize(path) if size > 16384: return (None, None,"File is too big") - fd = open(path, 'rb') - data = fd.read() + fdes = open(path, 'rb') + data = fdes.read() encoded = base64.encodestring(data) sha1 = hashlib.sha1(data).hexdigest() mime_type = mimetypes.guess_type(path)[0] return (encoded, mime_type, sha1) def get_output_of_command(command): + """ + Runs a command and returns its output + """ try: child_stdin, child_stdout = os.popen2(command) except ValueError: @@ -99,18 +114,16 @@ def is_in_path(command, return_abs_path=False): pass return False -distro_info = { +DISTRO_INFO = { 'Arch Linux': '/etc/arch-release', 'Aurox Linux': '/etc/aurox-release', 'Conectiva Linux': '/etc/conectiva-release', 'CRUX': '/usr/bin/crux', - 'Debian GNU/Linux': '/etc/debian_release', 'Debian GNU/Linux': '/etc/debian_version', 'Fedora Linux': '/etc/fedora-release', 'Gentoo Linux': '/etc/gentoo-release', 'Linux from Scratch': '/etc/lfs-release', 'Mandrake Linux': '/etc/mandrake-release', - 'Slackware Linux': '/etc/slackware-release', 'Slackware Linux': '/etc/slackware-version', 'Solaris/Sparc': '/etc/release', 'Source Mage': '/etc/sourcemage_version', @@ -122,52 +135,53 @@ distro_info = { # so Redhat is the last 'Redhat Linux': '/etc/redhat-release' } + +def temp_failure_retry(func, *args, **kwargs): + """ + workaround for a temporary and specific failure + """ + while True: + try: + return func(*args, **kwargs) + except (os.error, IOError, select.error), ex: + if ex.errno == errno.EINTR: + continue + else: + raise + def get_os_info(): - if os.name == 'nt': # could not happen, but... - ver = sys.getwindowsversion() - ver_format = ver[3], ver[0], ver[1] - win_version = { - (1, 4, 0): '95', - (1, 4, 10): '98', - (1, 4, 90): 'ME', - (2, 4, 0): 'NT', - (2, 5, 0): '2000', - (2, 5, 1): 'XP', - (2, 5, 2): '2003', - (2, 6, 0): 'Vista', - (2, 6, 1): '7', - } - if ver_format in win_version: - os_info = 'Windows' + ' ' + win_version[ver_format] - else: - os_info = 'Windows' - return os_info - elif os.name == 'posix': + """ + Returns a detailed and well formated string containing + informations about the operating system + """ + if os.name == 'posix': executable = 'lsb_release' params = ' --description --codename --release --short' full_path_to_executable = is_in_path(executable, return_abs_path = True) if full_path_to_executable: command = executable + params - p = subprocess.Popen([command], shell=True, stdin=subprocess.PIPE, - stdout=subprocess.PIPE, close_fds=True) - p.wait() - output = temp_failure_retry(p.stdout.readline).strip() + process = subprocess.Popen([command], shell=True, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + close_fds=True) + process.wait() + output = temp_failure_retry(process.stdout.readline).strip() # some distros put n/a in places, so remove those output = output.replace('n/a', '').replace('N/A', '') return output # lsb_release executable not available, so parse files - for distro_name in distro_info: - path_to_file = distro_info[distro_name] + for distro_name in DISTRO_INFO: + path_to_file = DISTRO_INFO[distro_name] if os.path.exists(path_to_file): if os.access(path_to_file, os.X_OK): # the file is executable (f.e. CRUX) # yes, then run it and get the first line of output. text = get_output_of_command(path_to_file)[0] else: - fd = open(path_to_file) - text = fd.readline().strip() # get only first line - fd.close() + fdes = open(path_to_file) + text = fdes.readline().strip() # get only first line + fdes.close() if path_to_file.endswith('version'): # sourcemage_version and slackware-version files # have all the info we need (name and version of distro) @@ -179,7 +193,8 @@ def get_os_info(): path_to_file.endswith('arch-release'): # file doesn't have version text = distro_name - elif path_to_file.endswith('lfs-release'): # file just has version + elif path_to_file.endswith('lfs-release'): + # file just has version text = distro_name + ' ' + text os_info = text.replace('\n', '') return os_info diff --git a/src/config.py b/src/config.py index 8237c7b7..1b9ba287 100644 --- a/src/config.py +++ b/src/config.py @@ -18,6 +18,11 @@ # You should have received a copy of the GNU General Public License # along with Poezio. If not, see . +""" +Defines the global config instance, used to get or set (and save) values +from/to the config file +""" + from ConfigParser import RawConfigParser, NoOptionError from os import environ, makedirs from shutil import copy2 @@ -39,7 +44,7 @@ class Config(RawConfigParser): The type of default defines the type returned """ - try: + try: if type(default) == int: res = self.getint(option) elif type(default) == float: @@ -52,45 +57,65 @@ class Config(RawConfigParser): return default return res - def _get(self, option): + def __get(self, option): + """ + facility for RawConfigParser.get + """ return RawConfigParser.get(self, self.defsection, option) def getstr(self, option): - return self._get(option) + """ + get a value and returns it as a string + """ + return self.__get(option) def getint(self, option): + """ + get a value and returns it as an int + """ try: - return int(self._get(option)) + return int(self.__get(option)) except ValueError: return -1 def getfloat(self, option): - return float(self._get(option)) + """ + get a value and returns it as a float + """ + return float(self.__get(option)) def getboolean(self, option): + """ + get a value and returns it as a boolean + """ return RawConfigParser.getboolean(self, self.defsection, option) - def set(self, option, value): - RawConfigParser.set(self, self.defsection, option, value) - def save(self): - f = open(self.file_name, "w") - RawConfigParser.write(self, f) - f.close() + """ + save the configuration in the file + """ + fdes = open(self.file_name, "w") + RawConfigParser.write(self, fdes) + fdes.close() def set_and_save(self, option, value): - self.set(option, value) + """ + set the value in the configuration then save it + to the file + """ + RawConfigParser.set(self, self.defsection, option, value) self.save() +# creates the configuration directory if it doesn't exist +# and copy the default config in it CONFIG_HOME = environ.get("XDG_CONFIG_HOME") if not CONFIG_HOME: CONFIG_HOME = environ.get('HOME')+'/.config' CONFIG_PATH = CONFIG_HOME + '/poezio/' - try: makedirs(CONFIG_PATH) copy2('../data/default_config.cfg', CONFIG_PATH+'poezio.cfg') -except:pass - +except OSError: + pass config = Config(CONFIG_PATH+'poezio.cfg') diff --git a/src/connection.py b/src/connection.py index a95191ba..b7326291 100644 --- a/src/connection.py +++ b/src/connection.py @@ -17,6 +17,10 @@ # You should have received a copy of the GNU General Public License # along with Poezio. If not, see . +""" +Defines the Connection class +""" + from gettext import (bindtextdomain, textdomain, bind_textdomain_codeset, gettext as _) @@ -35,7 +39,6 @@ from logging import logger from handler import Handler from common import exception_handler import threading -import thread class Connection(threading.Thread): """ @@ -77,74 +80,117 @@ class Connection(threading.Thread): {'host': config.get("proxy_server", ""), 'port': config.get("proxy_port", 1080), 'user': config.get("proxy_user", ""), - 'password': config.get("proxy_password", "") + 'password': config.get("proxy_password", + "") }) else: return self.client.connect((server, port)) def authenticate(self, anon=True): + """ + Authenticate to the server + """ if anon: try: self.client.auth(None, "", self.resource) return True except TypeError: - self.handler.emit('error', msg=_('Error: Could not authenticate. Please make sure the server you chose (%s) supports anonymous authentication' % (config.get('server', '')))) + self.handler.emit('error', msg=_('Error: Could not \ + authenticate. Please make sure the server you chose \ + (%s) supports anonymous authentication' + % (config.get('server', '')))) return None else: - log.error('Non-anonymous connections not handled currently') + logger.error('Non-anonymous connections not handled currently') return None def register_handlers(self): """ - register handlers from xmpppy signals + registers handlers from xmpppy signals """ - self.client.RegisterHandler('iq', self.on_get_time, typ='get', ns="urn:xmpp:time") - self.client.RegisterHandler('iq', self.on_get_version, typ='get', ns=xmpp.NS_VERSION) + self.client.RegisterHandler('iq', self.on_get_time, typ='get', + ns="urn:xmpp:time") + self.client.RegisterHandler('iq', self.on_get_version, typ='get', + ns=xmpp.NS_VERSION) self.client.RegisterHandler('presence', self.handler_presence) self.client.RegisterHandler('message', self.handler_message) def error_message(self, stanza): + """ + handles the error messages + """ room_name = stanza.getFrom().getStripped() - self.handler.emit('error-message', room=room_name, error=stanza.getTag('error'), msg=stanza.getError()) + self.handler.emit('error-message', room=room_name, + error=stanza.getTag('error'), + msg=stanza.getError()) raise xmpp.protocol.NodeProcessed def handler_presence(self, connection, presence): + """ + handles the presence messages + """ + if not connection: + return if presence.getType() == 'error': self.error_message(presence) return fro = presence.getFrom() - to = presence.getAttr('to') - if fro == to: # own presence + toj = presence.getAttr('to') + if fro == toj: # own presence self.online = 2 - self.jid = to + self.jid = toj self.handler.emit('on-connected', jid=fro) return self.handler.emit('room-presence', stanza=presence) raise xmpp.protocol.NodeProcessed def handler_delayed_message(self, connection, message): + """ + handles the delayed messages + These are received when we join a muc and we are sent the + recent history + """ + if not connection: + return self.handler.emit('room-delayed-message', stanza=message) raise xmpp.protocol.NodeProcessed def handler_message(self, connection, message): + """ + handles the common messages + """ + if not connection: + return if message.getType() == 'error': self.error_message(message) return self.handler.emit('room-message', stanza=message) raise xmpp.protocol.NodeProcessed - def handler_error(self, connection, error): - pass - def process(self, timeout=10): + """ + Main connection loop + It just waits for something to process (something is received + or something has to be sent) + """ if self.online: self.client.Process(timeout) else: - log.warning('disconnecting...') + logger.warning('disconnecting...') sys.exit() def on_get_version(self, connection, iq): + """ + Handles the iq requesting our software version + """ + if not connection: + return self.handler.emit('send-version', iq_obj=iq) def on_get_time(self, connection, iq): + """ + handles the iq requesting our time + """ + if not connection: + return self.handler.emit('send-time', iq_obj=iq) diff --git a/src/gui.py b/src/gui.py index f0b06af0..5f368266 100644 --- a/src/gui.py +++ b/src/gui.py @@ -17,12 +17,9 @@ # You should have received a copy of the GNU General Public License # along with Poezio. If not, see . -from common import debug - from gettext import (bindtextdomain, textdomain, bind_textdomain_codeset, gettext as _) - bindtextdomain('poezio') textdomain('poezio') bind_textdomain_codeset('poezio', 'utf-8') @@ -32,17 +29,11 @@ locale.setlocale(locale.LC_ALL, '') import sys import curses -import xmpp from datetime import datetime -from time import (altzone, daylight, gmtime, localtime, mktime, strftime, - time as time_time, timezone, tzname) -from calendar import timegm import common from handler import Handler -from logging import logger -from random import randrange from config import config from window import Window from user import User @@ -50,13 +41,13 @@ from room import Room class Gui(object): """ - Graphical user interface using ncurses + User interface using ncurses """ def __init__(self, stdscr=None, muc=None): self.room_number = 0 self.init_curses(stdscr) self.stdscr = stdscr - self.rooms = [Room('Info', '', self.next_room_number())] # current_room is self.rooms[0] + self.rooms = [Room('Info', '', self.next_room_number())] self.window = Window(stdscr) self.window.new_room(self.current_room()) self.window.refresh(self.rooms) @@ -65,26 +56,73 @@ class Gui(object): self.commands = { 'help': (self.command_help, _('OLOL, this is SOOO recursive')), - 'join': (self.command_join, _('Usage: /join [room_name][/nick] [password]\nJoin: Join the specified room. You can specify a nickname after a slash (/). If no nickname is specified, you will use the default_nick in the configuration file. You can omit the room name: you will then join the room you\'re looking at (useful if you were kicked). You can also provide a password to join the room.\nExamples:\n/join room@server.tld\n/join room@server.tld/John\n/join /me_again\n/join\n/join room@server.tld/my_nick password\n/join / pass')), - 'quit': (self.command_quit, _('Usage: /quit\nQuit: Just disconnect from the server and exit poezio.')), - 'exit': (self.command_quit, _('Usage: /exit\nExit: Just disconnect from the server and exit poezio.')), - 'next': (self.rotate_rooms_right, _('Usage: /next\nNext: Go to the next room.')), - 'n': (self.rotate_rooms_right, _('Usage: /n\nN: Go to the next room.')), - 'prev': (self.rotate_rooms_left, _('Usage: /prev\nPrev: Go to the previous room.')), - 'p': (self.rotate_rooms_left, _('Usage: /p\nP: Go to the previous room.')), - 'win': (self.command_win, _('Usage: /win \nWin: Go to the specified room.')), - 'w': (self.command_win, _('Usage: /w \nW: Go to the specified room.')), - 'part': (self.command_part, _('Usage: /part [message]\nPart: disconnect from a room. You can specify an optional message.')), - 'show': (self.command_show, _(u'Usage: /show [status]\nShow: Change your availability and (optionaly) your status. The argument is one of "avail, available, ok, here, chat, away, afk, dnd, busy, xa" and the optional [message] argument will be your status message')), - 'away': (self.command_away, _('Usage: /away [message]\nAway: Sets your availability to away and (optional) sets your status message. This is equivalent to "/show away [message]"')), - 'busy': (self.command_busy, _('Usage: /busy [message]\nBusy: Sets your availability to busy and (optional) sets your status message. This is equivalent to "/show busy [message]"')), - 'avail': (self.command_avail, _('Usage: /avail [message]\nAvail: Sets your availability to available and (optional) sets your status message. This is equivalent to "/show available [message]"')), - 'available': (self.command_avail, _('Usage: /available [message]\nAvailable: Sets your availability to available and (optional) sets your status message. This is equivalent to "/show available [message]"')), - 'bookmark': (self.command_bookmark, _('Usage: /bookmark [roomname][/nick]\nBookmark: Bookmark the specified room (you will then auto-join it on each poezio start). This commands uses the same syntaxe as /join. Type /help join for syntaxe examples. Note that when typing "/bookmark" on its own, the room will be bookmarked with the nickname you\'re currently using in this room (instead of default_nick)')), - 'set': (self.command_set, _('Usage: /set