Philipp Hörist pushed to branch master at gajim / gajim
Commits: 8df8486d by Markus Böhme at 2017-03-29T10:56:31+02:00 Add @unique decorator to all enumerations
Currently, there are no enumerations using the enum module which reuse values/need aliases. Add the @unique decorator to all enum classes as a safety net for future modifications.
- - - - - 167cf02a by Markus Böhme at 2017-03-29T10:56:31+02:00 Fix typo across codebase (change "tupple" to "tuple")
- - - - - d612e80a by Markus Böhme at 2017-03-30T21:23:03+02:00 Convert get_search_results_for_query to return named tuples
The get_search_results_for_query method in the logger module returns a list of bare tuples. Knowledge of how to pack and unpack the many indidual components of the tuples is scattered across both the callers and the callee, making the method hard to maintain and ugly to use. Therefore, convert the method to return named tuples instead.
- - - - - 08f4e171 by Markus Böhme at 2017-03-30T21:23:03+02:00 Rename method get_search_results_for_query to search_log
- - - - - 65e926c1 by Markus Böhme at 2017-03-30T21:24:31+02:00 Convert get_conversation_for_date to return named tuples
The get_conversation_for_date method in the logger module returns a list of bare tuples. Knowledge of how to pack and unpack the many individual components of the tuples is split between the caller and the callee, making the method hard to maintain and ugly to use. Therefore, convert the method to return named tuple instead.
- - - - - e735bfe7 by Markus Böhme at 2017-03-30T21:57:44+02:00 Make conversation loading in the history window use named tuples
The logger method get_conversation_for_date has previously been converted to return a list of named tuples. Now pass these tuples on to the method that actually inserts the conversation's messages into the textbuffer. Also rename two related methods in the history window: - _add_lines_for_date => _load_conversation - _add_new_line => _add_message
- - - - - 21d15dec by Markus Böhme at 2017-03-30T22:19:40+02:00 Use the same named tuple for related methods for conversation loading
Both methods get_conversation_for_date and search_log in the logger module are related to the loading of conversations and both return a list of messages from the log. Therefore, it makes sense that both of them have the same return type.
Remove the named tuple type specific to search_log and convert the method to return tuples of type Message instead. As a side effect of this change, search_log now also returns values from the additional_data column in the log database.
- - - - - 1a5d6fbf by Philipp Hörist at 2017-03-31T16:44:32+02:00 Merge branch 'various-cleanups' into 'master'
Various small cleanups, with focus on logger and history window
See merge request !77 - - - - -
16 changed files:
- src/advanced_configuration_window.py - src/command_system/implementation/standard.py - src/common/config.py - src/common/configpaths.py - src/common/jingle_ft.py - src/common/jingle_session.py - src/common/jingle_transport.py - src/common/logger.py - src/common/zeroconf/zeroconf.py - src/filetransfers_window.py - src/groupchat_control.py - src/history_manager.py - src/history_window.py - src/message_control.py - src/plugins/gui.py - src/roster_window.py
Changes:
===================================== src/advanced_configuration_window.py ===================================== --- a/src/advanced_configuration_window.py +++ b/src/advanced_configuration_window.py @@ -23,7 +23,7 @@ ## along with Gajim. If not, see http://www.gnu.org/licenses/. ##
-from enum import IntEnum +from enum import IntEnum, unique
from gi.repository import Gtk import gtkgui_helpers @@ -32,6 +32,7 @@ from gi.repository import Pango
from common import gajim
+@unique class Column(IntEnum): PREFERENCE_NAME = 0 VALUE = 1
===================================== src/command_system/implementation/standard.py ===================================== --- a/src/command_system/implementation/standard.py +++ b/src/command_system/implementation/standard.py @@ -87,8 +87,7 @@ class StandardCommonCommands(CommandContainer): @command('lastlog', overlap=True) @doc(_("Show logged messages which mention given text")) def grep(self, text, limit=None): - results = gajim.logger.get_search_results_for_query(self.contact.jid, - text, self.account) + results = gajim.logger.search_log(self.contact.jid, text, self.account)
if not results: raise CommandError(_("%s: Nothing found") % text) @@ -100,23 +99,22 @@ class StandardCommonCommands(CommandContainer): raise CommandError(_("Limit must be an integer"))
for row in results: - contact, time, kind, show, message, subject, log_line_id = row - + contact = row.contact_name if not contact: - if kind == KindConstant.CHAT_MSG_SENT: + if row.kind == KindConstant.CHAT_MSG_SENT: contact = gajim.nicks[self.account] else: contact = self.contact.name
- time_obj = localtime(time) - date_obj = date.fromtimestamp(time) + time_obj = localtime(row.time) + date_obj = date.fromtimestamp(row.time) date_ = strftime('%Y-%m-%d', time_obj) time_ = strftime('%H:%M:%S', time_obj)
if date_obj == date.today(): - formatted = "[%s] %s: %s" % (time_, contact, message) + formatted = "[%s] %s: %s" % (time_, contact, row.message) else: - formatted = "[%s, %s] %s: %s" % (date_, time_, contact, message) + formatted = "[%s, %s] %s: %s" % (date_, time_, contact, row.message)
self.echo(formatted)
===================================== src/common/config.py ===================================== --- a/src/common/config.py +++ b/src/common/config.py @@ -35,8 +35,9 @@ import re from common import defs from gi.repository import GLib -from enum import IntEnum +from enum import IntEnum, unique
+@unique class Option(IntEnum): TYPE = 0 VAL = 1
===================================== src/common/configpaths.py ===================================== --- a/src/common/configpaths.py +++ b/src/common/configpaths.py @@ -26,8 +26,9 @@ import os import sys import tempfile from common import defs -from enum import Enum +from enum import Enum, unique
+@unique class Type(Enum): CONFIG = 0 CACHE = 1
===================================== src/common/jingle_ft.py ===================================== --- a/src/common/jingle_ft.py +++ b/src/common/jingle_ft.py @@ -23,7 +23,7 @@ import hashlib import logging import os import threading -from enum import IntEnum +from enum import IntEnum, unique import nbxmpp from common import gajim from common import configpaths @@ -39,6 +39,7 @@ from common.jingle_ftstates import ( log = logging.getLogger('gajim.c.jingle_ft')
+@unique class State(IntEnum): NOT_STARTED = 0 INITIALIZED = 1
===================================== src/common/jingle_session.py ===================================== --- a/src/common/jingle_session.py +++ b/src/common/jingle_session.py @@ -29,7 +29,7 @@ Handles Jingle sessions (XEP 0166) # * timeout
import logging -from enum import Enum +from enum import Enum, unique import nbxmpp from common import gajim from common.jingle_transport import get_jingle_transport, JingleTransportIBB @@ -43,6 +43,7 @@ from common.connection_handlers_events import ( log = logging.getLogger("gajim.c.jingle_session")
# FIXME: Move it to JingleSession.States? +@unique class JingleStates(Enum): """ States in which jingle session may exist
===================================== src/common/jingle_transport.py ===================================== --- a/src/common/jingle_transport.py +++ b/src/common/jingle_transport.py @@ -19,7 +19,7 @@ Handles Jingle Transports (currently only ICE-UDP)
import logging import socket -from enum import IntEnum +from enum import IntEnum, unique import nbxmpp from common import gajim
@@ -34,6 +34,7 @@ def get_jingle_transport(node): return transports[namespace](node)
+@unique class TransportType(IntEnum): """ Possible types of a JingleTransport
===================================== src/common/logger.py ===================================== --- a/src/common/logger.py +++ b/src/common/logger.py @@ -33,10 +33,11 @@ import sys import time import datetime import json +from collections import namedtuple from gzip import GzipFile from io import BytesIO from gi.repository import GLib -from enum import IntEnum +from enum import IntEnum, unique
from common import exceptions from common import gajim @@ -51,10 +52,12 @@ CACHE_DB_PATH = gajim.gajimpaths['CACHE_DB'] import logging log = logging.getLogger('gajim.c.logger')
+@unique class JIDConstant(IntEnum): NORMAL_TYPE = 0 ROOM_TYPE = 1
+@unique class KindConstant(IntEnum): STATUS = 0 GCSTATUS = 1 @@ -65,6 +68,7 @@ class KindConstant(IntEnum): CHAT_MSG_SENT = 6 ERROR = 7
+@unique class ShowConstant(IntEnum): ONLINE = 0 CHAT = 1 @@ -73,6 +77,7 @@ class ShowConstant(IntEnum): DND = 4 OFFLINE = 5
+@unique class TypeConstant(IntEnum): AIM = 0 GG = 1 @@ -90,6 +95,7 @@ class TypeConstant(IntEnum): MRIM = 13 NO_TRANSPORT = 14
+@unique class SubscriptionConstant(IntEnum): NONE = 0 TO = 1 @@ -182,7 +188,7 @@ class Logger: def get_jids_already_in_db(self): try: self.cur.execute('SELECT jid FROM jids') - # list of tupples: [('aaa@bbb',), ('cc@dd',)] + # list of tuples: [('aaa@bbb',), ('cc@dd',)] rows = self.cur.fetchall() except sqlite.DatabaseError: raise exceptions.DatabaseMalformed @@ -583,8 +589,8 @@ class Logger: """ Accept how many rows to restore and when to time them out (in minutes) (mark them as too old) and number of messages that are in queue and are - already logged but pending to be viewed, returns a list of tupples - containg time, kind, message, sibject list with empty tupple if nothing + already logged but pending to be viewed, returns a list of tuples + containg time, kind, message, subject list with empty tuple if nothing found to meet our demands """ try: @@ -625,17 +631,27 @@ class Logger: # returns time in seconds for the second that starts that date since epoch # gimme unixtime from year month day: d = datetime.date(year, month, day) - local_time = d.timetuple() # time tupple (compat with time.localtime()) + local_time = d.timetuple() # time tuple (compat with time.localtime()) # we have time since epoch baby :) start_of_day = int(time.mktime(local_time)) return start_of_day
+ Message = namedtuple('Message', + ['contact_name', 'time', 'kind', 'show', 'message', 'subject', + 'additional_data', 'log_line_id']) + def get_conversation_for_date(self, jid, year, month, day, account): """ - Return contact_name, time, kind, show, message, subject, additional_data, log_line_id + Load the complete conversation with a given jid on a specific date + + The conversation contains all messages that were exchanged between + `account` and `jid` on the day specified by `year`, `month` and `day`, + where `month` and `day` are 1-based.
- For each row in a list of tupples, returns list with empty tupple if we - found nothing to meet our demands + The conversation will be returned as a list of single messages of type + `Logger.Message`. Messages in the list are sorted chronologically. An + empty list will be returned if there are no messages in the log database + for the requested combination of `jid` and `account` on the given date. """ try: self.get_jid_id(jid) @@ -657,22 +673,23 @@ class Logger: ORDER BY time ''' % (where_sql, start_of_day, last_second_of_day), jid_tuple)
- results = self.cur.fetchall() - messages = [] - for entry in results: - additional_data = json.loads(entry[6]) - parsed_entry = entry[:6] + (additional_data, ) + entry[7:] - messages.append(parsed_entry) + results = [self.Message(*row) for row in self.cur.fetchall()] + for message in results: + message._replace(additional_data=json.loads(message.additional_data))
- return messages + return results
- def get_search_results_for_query(self, jid, query, account, year=False, - month=False, day=False): + def search_log(self, jid, query, account, year=None, month=None, day=None): """ - Returns contact_name, time, kind, show, message, subject, log_line_id + Search the conversation log for messages containing the `query` string. + + The search can either span the complete log for the given `account` and + `jid` or be restriced to a single day by specifying `year`, `month` and + `day`, where `month` and `day` are 1-based.
- For each row in a list of tupples, returns list with empty tupple if we - found nothing to meet our demands + All messages matching the specified criteria will be returned in a list + containing tuples of type `Logger.Message`. If no messages match the + criteria, an empty list will be returned. """ try: self.get_jid_id(jid) @@ -682,12 +699,14 @@ class Logger:
where_sql, jid_tuple = self._build_contact_where(account, jid) like_sql = '%' + query.replace("'", "''") + '%' - if year: + if year and month and day: start_of_day = self.get_unix_time_from_date(year, month, day) seconds_in_a_day = 86400 # 60 * 60 * 24 last_second_of_day = start_of_day + seconds_in_a_day - 1 self.cur.execute(''' - SELECT contact_name, time, kind, show, message, subject, log_line_id FROM logs + SELECT contact_name, time, kind, show, message, subject, + additional_data, log_line_id + FROM logs WHERE (%s) AND message LIKE '%s' AND time BETWEEN %d AND %d ORDER BY time @@ -695,12 +714,17 @@ class Logger: jid_tuple) else: self.cur.execute(''' - SELECT contact_name, time, kind, show, message, subject, log_line_id FROM logs + SELECT contact_name, time, kind, show, message, subject, + additional_data, log_line_id + FROM logs WHERE (%s) AND message LIKE '%s' ORDER BY time ''' % (where_sql, like_sql), jid_tuple)
- results = self.cur.fetchall() + results = [self.Message(*row) for row in self.cur.fetchall()] + for message in results: + message._replace(additional_data=json.loads(message.additional_data)) + return results
def get_days_with_logs(self, jid, year, month, max_day, account):
===================================== src/common/zeroconf/zeroconf.py ===================================== --- a/src/common/zeroconf/zeroconf.py +++ b/src/common/zeroconf/zeroconf.py @@ -17,8 +17,9 @@ ## along with Gajim. If not, see http://www.gnu.org/licenses/. ##
-from enum import IntEnum +from enum import IntEnum, unique
+@unique class Constant(IntEnum): NAME = 0 DOMAIN = 1 @@ -26,6 +27,7 @@ class Constant(IntEnum): BARE_NAME = 3 TXT = 4
+@unique class ConstantRI(IntEnum): INTERFACE = 0 PROTOCOL = 1
===================================== src/filetransfers_window.py ===================================== --- a/src/filetransfers_window.py +++ b/src/filetransfers_window.py @@ -29,7 +29,7 @@ from gi.repository import Pango import os import time
-from enum import IntEnum +from enum import IntEnum, unique
import gtkgui_helpers import tooltips @@ -44,6 +44,7 @@ from nbxmpp.protocol import NS_JINGLE_FILE_TRANSFER import logging log = logging.getLogger('gajim.filetransfer_window')
+@unique class Column(IntEnum): IMAGE = 0 LABELS = 1
===================================== src/groupchat_control.py ===================================== --- a/src/groupchat_control.py +++ b/src/groupchat_control.py @@ -46,7 +46,7 @@ import cell_renderer_image import dataforms_widget import nbxmpp
-from enum import IntEnum +from enum import IntEnum, unique
from common import events from common import gajim @@ -65,6 +65,7 @@ from common.connection_handlers_events import GcMessageOutgoingEvent import logging log = logging.getLogger('gajim.groupchat_control')
+@unique class Column(IntEnum): IMG = 0 # image to show state (online, new message etc) NICK = 1 # contact nickame or ROLE name
===================================== src/history_manager.py ===================================== --- a/src/history_manager.py +++ b/src/history_manager.py @@ -77,8 +77,9 @@ from common.logger import LOG_DB_PATH, JIDConstant, KindConstant from common import helpers import dialogs
-from enum import IntEnum +from enum import IntEnum, unique
+@unique class Column(IntEnum): UNIXTIME = 2 MESSAGE = 3 @@ -252,7 +253,7 @@ class HistoryManager: # get those jids that have at least one entry in logs self.cur.execute('SELECT jid, jid_id FROM jids WHERE jid_id IN (' 'SELECT distinct logs.jid_id FROM logs) ORDER BY jid') - # list of tupples: [('aaa@bbb',), ('cc@dd',)] + # list of tuples: [('aaa@bbb',), ('cc@dd',)] rows = self.cur.fetchall() for row in rows: self.jids_already_in.append(row[0]) # jid
===================================== src/history_window.py ===================================== --- a/src/history_window.py +++ b/src/history_window.py @@ -31,7 +31,7 @@ from gi.repository import GLib import time import calendar
-from enum import IntEnum +from enum import IntEnum, unique
import gtkgui_helpers import conversation_textview @@ -43,6 +43,7 @@ from common import exceptions
from common.logger import ShowConstant, KindConstant
+@unique class InfoColumn(IntEnum): '''Completion dict''' JID = 0 @@ -50,6 +51,7 @@ class InfoColumn(IntEnum): NAME = 2 COMPLETION = 3
+@unique class Column(IntEnum): LOG_JID = 0 CONTACT_NAME = 1 @@ -340,7 +342,7 @@ class HistoryWindow: return year, month, day = self.calendar.get_date() # integers month = gtkgui_helpers.make_gtk_month_python_month(month) - self._add_lines_for_date(year, month, day) + self._load_conversation(year, month, day)
def on_calendar_month_changed(self, widget): """ @@ -385,34 +387,38 @@ class HistoryWindow:
return show
- def _add_lines_for_date(self, year, month, day): + def _load_conversation(self, year, month, day): """ - Add all the lines for given date in textbuffer + Load the conversation between `self.jid` and `self.account` held on the + given date into the history textbuffer. Values for `month` and `day` + are 1-based. """ - self.history_buffer.set_text('') # clear the buffer first + self.history_buffer.set_text('') self.last_time_printout = 0 show_status = self.show_status_checkbutton.get_active()
- lines = gajim.logger.get_conversation_for_date(self.jid, year, month, day, self.account) - for line in lines: - # line[0] is contact_name, line[1] is time of message - # line[2] is kind, line[3] is show, line[4] is message, line[5] is subject - # line[6] is additional_data, line[7] is log_line_id - if not show_status and line[2] in (KindConstant.GCSTATUS, - KindConstant.STATUS): + conversation = gajim.logger.get_conversation_for_date( + self.jid, year, month, day, self.account) + for message in conversation: + if not show_status and message.kind in (KindConstant.GCSTATUS, + KindConstant.STATUS): continue - self._add_new_line(line[0], line[1], line[2], line[3], line[4], - line[5], line[6], line[7]) + self._add_message(message)
- def _add_new_line(self, contact_name, tim, kind, show, message, subject, - additional_data, log_line_id): - """ - Add a new line in textbuffer - """ - if not message and kind not in (KindConstant.STATUS, - KindConstant.GCSTATUS): + def _add_message(self, msg): + if not msg.message and msg.kind not in (KindConstant.STATUS, + KindConstant.GCSTATUS): return
+ tim = msg.time + kind = msg.kind + show = msg.show + message = msg.message + subject = msg.subject + log_line_id = msg.log_line_id + contact_name = msg.contact_name + additional_data = msg.additional_data + buf = self.history_buffer end_iter = buf.get_end_iter()
@@ -423,7 +429,7 @@ class HistoryWindow: timestamp_str = gajim.config.get('time_stamp') timestamp_str = helpers.from_one_line(timestamp_str) tim = time.strftime(timestamp_str, time.localtime(float(tim))) - buf.insert(end_iter, tim) # add time + buf.insert(end_iter, tim) elif gajim.config.get('print_time') == 'sometimes': every_foo_seconds = 60 * gajim.config.get( 'print_ichat_every_foo_minutes') @@ -441,13 +447,11 @@ class HistoryWindow:
if kind == KindConstant.GC_MSG: tag_name = 'incoming' - elif kind in (KindConstant.SINGLE_MSG_RECV, - KindConstant.CHAT_MSG_RECV): + elif kind in (KindConstant.SINGLE_MSG_RECV, KindConstant.CHAT_MSG_RECV): contact_name = self.completion_dict[self.jid][InfoColumn.NAME] tag_name = 'incoming' tag_msg = 'incomingtxt' - elif kind in (KindConstant.SINGLE_MSG_SENT, - KindConstant.CHAT_MSG_SENT): + elif kind in (KindConstant.SINGLE_MSG_SENT, KindConstant.CHAT_MSG_SENT): if self.account: contact_name = gajim.nicks[self.account] else: @@ -539,33 +543,27 @@ class HistoryWindow: month = gtkgui_helpers.make_gtk_month_python_month(month)
show_status = self.show_status_checkbutton.get_active() - - # contact_name, time, kind, show, message, subject - results = gajim.logger.get_search_results_for_query( - jid, text, account, year, month, day) + results = gajim.logger.search_log(jid, text, account, year, month, day) #FIXME: # add "subject: | message: " in message column if kind is single # also do we need show at all? (we do not search on subject) for row in results: - if not show_status and row[2] in (KindConstant.GCSTATUS, - KindConstant.STATUS): + if not show_status and row.kind in (KindConstant.GCSTATUS, + KindConstant.STATUS): continue - contact_name = row[0] + + contact_name = row.contact_name if not contact_name: - kind = row[2] - if kind == KindConstant.CHAT_MSG_SENT: # it's us! :) + if row.kind == KindConstant.CHAT_MSG_SENT: # it's us! :) contact_name = gajim.nicks[account] else: contact_name = self.completion_dict[jid][InfoColumn.NAME] - tim = row[1] - message = row[4] - log_line_id = row[6] - local_time = time.localtime(tim) + + local_time = time.localtime(row.time) date = time.strftime('%Y-%m-%d', local_time)
- # jid (to which log is assigned to), name, date, message, - # time (full unix time) - model.append((jid, contact_name, date, message, str(tim), log_line_id)) + model.append((jid, contact_name, date, row.message, + str(row.time), row.log_line_id))
def on_results_treeview_row_activated(self, widget, path, column): """ @@ -576,7 +574,7 @@ class HistoryWindow: cur_year, cur_month, cur_day = self.calendar.get_date() cur_month = gtkgui_helpers.make_gtk_month_python_month(cur_month) model = widget.get_model() - # make it a tupple (Y, M, D, 0, 0, 0...) + # make it a tuple (Y, M, D, 0, 0, 0...) tim = time.strptime(model[path][Column.UNIXTIME], '%Y-%m-%d') year = tim[0] gtk_month = tim[1]
===================================== src/message_control.py ===================================== --- a/src/message_control.py +++ b/src/message_control.py @@ -157,7 +157,7 @@ class MessageControl(object):
Derivded classes MUST implement this. """ - # Return a markup'd label and optional Gtk.Color in a tupple like: + # Return a markup'd label and optional Gtk.Color in a tuple like: # return (label_str, None) pass
===================================== src/plugins/gui.py ===================================== --- a/src/plugins/gui.py +++ b/src/plugins/gui.py @@ -32,7 +32,7 @@ from gi.repository import GdkPixbuf from gi.repository import GLib, Gdk import os
-from enum import IntEnum +from enum import IntEnum, unique
import gtkgui_helpers from dialogs import WarningDialog, YesNoDialog, ArchiveChooserDialog @@ -43,6 +43,7 @@ from plugins.helpers import GajimPluginActivateException from plugins.plugins_i18n import _ from common.exceptions import PluginsystemError
+@unique class Column(IntEnum): PLUGIN = 0 NAME = 1
===================================== src/roster_window.py ===================================== --- a/src/roster_window.py +++ b/src/roster_window.py @@ -43,7 +43,7 @@ import os import time import locale
-from enum import IntEnum +from enum import IntEnum, unique
import common.sleepy import history_window @@ -69,6 +69,7 @@ from message_window import MessageWindowMgr from nbxmpp.protocol import NS_FILE, NS_ROSTERX, NS_CONFERENCE
+@unique class Column(IntEnum): IMG = 0 # image to show state (online, new message etc) NAME = 1 # cellrenderer text that holds contact nickame @@ -5792,7 +5793,7 @@ class RosterWindow: self._iters = {} # for merged mode self._iters['MERGED'] = {'account': None, 'groups': {}} - # holds a list of (jid, account) tupples + # holds a list of (jid, account) tuples self._last_selected_contact = [] self.transports_state_images = {'16': {}, '32': {}, 'opened': {}, 'closed': {}}
View it on GitLab: https://dev.gajim.org/gajim/gajim/compare/2f1cad1c8133ce36100705b7a7be6e7ae6...