[Telepathy-commits] [telepathy-pinocchio/master] refactor some objects and methods for readability and simplicity

Travis Reitter travis.reitter at collabora.co.uk
Wed Aug 13 17:31:30 PDT 2008


---
 pinocchio/channel/contact_list.py |    8 +-
 pinocchio/common.py               |   30 +++++---
 pinocchio/connection/__init__.py  |    1 -
 pinocchio/server/__init__.py      |  147 ++++++++++++-------------------------
 4 files changed, 71 insertions(+), 115 deletions(-)

diff --git a/pinocchio/channel/contact_list.py b/pinocchio/channel/contact_list.py
index 6185f6c..bda8b52 100644
--- a/pinocchio/channel/contact_list.py
+++ b/pinocchio/channel/contact_list.py
@@ -25,7 +25,7 @@ import pinocchio as pin
 class ContactList(tp.server.ChannelTypeContactList,
                   tp.server.ChannelInterfaceGroup):
     """
-    Set of all contacts 
+    Set of contacts corresponding to a Telepathy ContactList channel.
     
     Implements DBus interface org.freedesktop.Telepathy.Channel.Interface.Group
     """
@@ -37,14 +37,16 @@ class ContactList(tp.server.ChannelTypeContactList,
 
         self._connection = connection
         self.account_id = account_id
-        contacts_disk = pin.server.ContactList(connection, channel_handle_obj)
+        contacts_disk = pin.server.StoredContactList(connection,
+                                                     channel_handle_obj)
 
-        handles_initial = contacts_disk.create_handles(connection)
+        handles_initial = contacts_disk.get_handle_objs()
         for handle_obj in handles_initial:
             connection._handles[tp.constants.HANDLE_TYPE_CONTACT,
                                 handle_obj.get_id()] = handle_obj
 
         # send initial member list as any other list change
+        # this stores these HandleContact objects in self._members
         self.MembersChanged('', handles_initial, (), (), (), 0,
                             tp.constants.CHANNEL_GROUP_CHANGE_REASON_NONE)
 
diff --git a/pinocchio/common.py b/pinocchio/common.py
index f0cfb6f..a2f20b4 100644
--- a/pinocchio/common.py
+++ b/pinocchio/common.py
@@ -26,6 +26,7 @@ PROTO_DEFAULT = 'dummy'
 ACCOUNT_DEFAULT = 'default at default'
 
 CONTACTS_FILE_DEFAULT='contacts.xml'
+CONTACTS_FILE_MODIFIED='contacts-modified.xml'
 # XXX: is there a better place to default to?
 DATA_DIR_DEFAULT = '/var/lib/telepathy-pinocchio'
 AVATAR_DIR_DEFAULT = os.path.join(DATA_DIR_DEFAULT, 'avatars')
@@ -40,11 +41,13 @@ def get_account_dir(account_id=None):
 
 def get_contacts_file_abs(contacts_file=None, account_id=None):
     """Returns the absolute path for the contacts file (prepending the account's
-    base data dir as necessary).
+    base data dir as necessary). Modified rosters are saved to disk as a
+    different name, so this function prefers them over the default file name.
 
     Arguments:
-    contacts_file -- given contacts file argument, or None to use the default
-                     (default: None)
+    contacts_file -- CONTACTS_FILE_DEFAULT to get the unmodified contacts file
+                     CONTACTS_FILE_MODIFIED to get the modified contacst file
+                     None to get the modified file if it exists, else default
     account -- raw name of the account (default: ACCOUNT_DEFAULT)
 
     Returns:
@@ -56,15 +59,22 @@ def get_contacts_file_abs(contacts_file=None, account_id=None):
 
     account_dir = get_account_dir(account_id)
 
-    if contacts_file == None:
-        contacts_file = os.path.join(account_dir, CONTACTS_FILE_DEFAULT)
+    contacts_file_final = None
 
-    # determine the absolute path for this file (based on the account's
-    # personal data dir)
-    if not os.path.isabs(contacts_file):
-        contacts_file = os.path.join(account_dir, contacts_file)
+    if   contacts_file in (CONTACTS_FILE_DEFAULT, CONTACTS_FILE_MODIFIED):
+        contacts_file_final = os.path.join(account_dir, CONTACTS_FILE_MODIFIED)
+    elif contacts_file == None:
+        # if contact list has been modified, it will be saved with this name
+        contacts_file_final = os.path.join(account_dir, CONTACTS_FILE_MODIFIED)
 
-    return contacts_file
+        # otherwise, use the default file path
+        if not os.path.isfile(contacts_file_final):
+            contacts_file_final = os.path.join(account_dir,
+                                               CONTACTS_FILE_DEFAULT)
+    else:
+        raise ValueError, 'invalid contacts file argument'
+
+    return contacts_file_final
 
 def image_filename_to_mime_type(file_path):
     """Get the MIME type for a given image file. The image's MIME type will be
diff --git a/pinocchio/connection/__init__.py b/pinocchio/connection/__init__.py
index d691c7d..ae91dfa 100644
--- a/pinocchio/connection/__init__.py
+++ b/pinocchio/connection/__init__.py
@@ -36,7 +36,6 @@ class Connection(tp.server.Connection,
 
     _CONTACT_LIST_NAMES = ('subscribe', 'publish', 'hide', 'allow', 'deny')
 
-    # TODO: this should probably include logging file destinations
     _optional_parameters = {'password': 's', 'register': 'b'}
     _mandatory_parameters = {'account': 's'}
     _parameter_defaults = {'account': pin.common.ACCOUNT_DEFAULT}
diff --git a/pinocchio/server/__init__.py b/pinocchio/server/__init__.py
index 5a52b74..e1205a7 100644
--- a/pinocchio/server/__init__.py
+++ b/pinocchio/server/__init__.py
@@ -152,53 +152,11 @@ class HandleContact(tp.server.Handle):
     def set_status_message(self, status_message):
         self._extended_attrs['status_message'] = status_message
 
-class _Contact:
-    """
-    Internal representation of a Contact, based on XML representation.
-    """
-
-    def __init__(self, contact_xml):
-        self.metadata = {}
-
-        for key in ['alias', 'username', 'avatar_path']:
-            try:
-                value_tag = contact_xml.getElementsByTagName(key)[0]
-                value = value_tag.firstChild.data
-            except:
-                value = ''
-
-            self.metadata[key] = value
-
-    def to_xml(self):
-        """Returns xml.dom.minidom.Document representation of Contact.
-        
-        Internally, this XML is structured as:
-
-            <contact>
-                <attr_1>value_1</attr_1>
-                ...
-                <attr_n>value_n</attr_n>
-            </contact>
-        """
-        impl = minidom.getDOMImplementation()
-        xml_file = impl.createDocument(None, 'contact', None)
-        root = xml_file.documentElement
-
-        for attr_name in self.metadata.keys():
-            # <attr_name>value</attr_name>
-            attr = xml_file.createElement(attr_name)
-            attr.appendChild(xml_file.createTextNode(self.metadata[attr_name]))
-
-            root.appendChild(attr)
-
-        return xml_file
-
-
-class ContactList:
+class StoredContactList:
     def __init__(self, connection, channel_handle_obj):
         """
         Arguments:
-        connection -- connection this ContactList corresponds to
+        connection -- connection this StoredContactList corresponds to
         channel_handle_obj -- handle object of the channel this list maps to
 
         Exceptions:
@@ -211,13 +169,9 @@ class ContactList:
         try:
             contacts_file = open(self.connection._contacts_file, 'rU')
         except:
-            print 'Could not open contact list file. Falling back to default!'
-
-            try:
-                contacts_file = open(pin.common.get_contacts_file_abs (), 'rU')
-            except:
-                print 'Could not open default contact list'
-                raise
+            print 'Could not open contact list file ', \
+                                                 self.connection._contacts_file
+            raise
 
         contacts_xml = minidom.parse(contacts_file)
         contacts_file.close()
@@ -240,9 +194,46 @@ class ContactList:
             lists = contact.getElementsByTagName('list')
             for list in lists:
                 if list.firstChild.data == channel_name:
-                    self.contacts.append(_Contact(contact))
+                    handle_contact = self.contact_xml_to_handle(contact,
+                                                                connection)
+
+                    self.contacts.append(handle_contact)
                     break
 
+    def get_handle_objs(self):
+        return self.contacts
+
+    def contact_xml_to_handle(self, contact_xml, connection):
+        handle_contact = None
+        extended_attrs = {}
+
+        try:
+            username_tag = contact_xml.getElementsByTagName('username')[0]
+            username = username_tag.firstChild.data
+        except:
+            raise ValueError, 'contact has no username'
+
+        CONTACT_HANDLE = tp.constants.HANDLE_TYPE_CONTACT
+        id, id_is_new = connection.get_handle_id_idempotent(CONTACT_HANDLE,
+                                                            username)
+        # only create HandleContact objects as necessary (to avoid unwanted
+        # side-effects in the form of duplicate signals)
+        if id_is_new:
+            extended_attrs = {}
+            for attr in ('alias', 'avatar_path', 'status', 'status_message'):
+                try:
+                    value_tag = contact_xml.getElementsByTagName(attr)[0]
+                    extended_attrs[attr] = value_tag.firstChild.data
+                except:
+                    pass
+            
+            handle_contact = HandleContact(id, username, connection,
+                                           extended_attrs)
+        else:
+            handle_contact = connection._handles[CONTACT_HANDLE, id]
+
+        return handle_contact
+
     def to_xml(self):
         """Returns xml.dom.minidom.Document representation of full Contact List.
         
@@ -271,7 +262,9 @@ class ContactList:
         """Write contact list to XML file on disk.
 
         Arguments:
-        file_src -- XML file containing contact list
+        file_dest -- XML file containing contact list (default:
+                     ${ACCOUNT_DIR}/contacts-modified.xml)
+
 
         Exceptions:
         IOError -- failed to read contact list file
@@ -290,51 +283,3 @@ class ContactList:
         contacts_file.write(xml_contents.encode('utf-8'))
 
         contacts_file.close()
-
-    def get_contact(self, username):
-        """Returns an arbitrary contact matching the given username (if any), or
-        None.
-
-        Arguments:
-        username -- string of username
-
-        Returns:
-        contact -- server._Contact for the contact in this list if matched
-        """
-        for (contact, name) in self.contacts.items():
-            if name == username:
-                return contact
-
-        return None
-
-    def create_handles(self, connection):
-        """Returns a set of HandleContact objects for this list's contacts
-        (creating new handles within the connection only as necessary).
-
-        Arguments:
-        connection -- telepathy.server.Connection to get/create handles within
-        """
-        CONTACT_HANDLE = tp.constants.HANDLE_TYPE_CONTACT
-
-        handles = set()
-        for contact in self.contacts:
-            username = contact.metadata['username']
-            id, id_is_new = connection.get_handle_id_idempotent(CONTACT_HANDLE,
-                                                                username)
-
-            # only create HandleContact objects as necessary (to avoid unwanted
-            # side-effects in the form of duplicate signals)
-            if id_is_new:
-                extended_attrs = {}
-                for attr in ('alias', 'avatar_path', 'status',
-                             'status_message'):
-                    if attr in contact.metadata:
-                        extended_attrs[attr] = contact.metadata[attr]
-                
-                handles.update((HandleContact(id, username, connection,
-                                              extended_attrs),))
-            else:
-                handle_existing = connection._handles[CONTACT_HANDLE, id]
-                handles.update((handle_existing,))
-
-        return handles
-- 
1.5.6.3




More information about the Telepathy-commits mailing list