Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/sugar/presence
diff options
context:
space:
mode:
authorMike C. Fletcher <mcfletch@raistlin.(none)>2007-04-15 03:38:21 (GMT)
committer Mike C. Fletcher <mcfletch@raistlin.(none)>2007-04-15 03:38:21 (GMT)
commit0fc5e67dcc8da935ef7972a18893eb6c8e04f357 (patch)
treee6efde9e006c946689a7be6abb1983dd53fa95c4 /sugar/presence
parenta2de1f7f3fa5ecec7d4004be3fb839932a938389 (diff)
More documentation, mostly for the sugar.presence.presenceservice
module.
Diffstat (limited to 'sugar/presence')
-rw-r--r--sugar/presence/__init__.py7
-rw-r--r--sugar/presence/presenceservice.py147
2 files changed, 153 insertions, 1 deletions
diff --git a/sugar/presence/__init__.py b/sugar/presence/__init__.py
index e69de29..f09a5e3 100644
--- a/sugar/presence/__init__.py
+++ b/sugar/presence/__init__.py
@@ -0,0 +1,7 @@
+"""Client-code's interface to the PresenceService
+
+Provides a simplified API for accessing the dbus service
+which coordinates native network presence and sharing
+information. This includes both "buddies" and "shared
+activities".
+"""
diff --git a/sugar/presence/presenceservice.py b/sugar/presence/presenceservice.py
index 9b7bd3c..78f51e6 100644
--- a/sugar/presence/presenceservice.py
+++ b/sugar/presence/presenceservice.py
@@ -1,3 +1,4 @@
+"""UI class to access system-level presence object"""
# Copyright (C) 2007, Red Hat, Inc.
#
# This library is free software; you can redistribute it and/or
@@ -18,24 +19,78 @@
import dbus, dbus.glib, gobject
import logging
+# XXX use absolute imports
+# from sugar.presence import buddy, activity
+# this *kind* of relative import is deprecated
+# with an explicit relative import slated to be
+# introduced (available in Python 2.5 with a __future__
+# import), that would read as:
+# from . import buddy, activity
+# see PEP: http://docs.python.org/whatsnew/pep-328.html
import buddy, activity
class ObjectCache(object):
+ """Path to Activity/Buddy object cache
+
+ On notification of a new object of either type the
+ PresenceService client stores the object's representation
+ in this object.
+
+ XXX Why not just sub-class dict? We're only adding two
+ methods then and we would have all of the other
+ standard operations on dictionaries.
+ """
def __init__(self):
+ """Initialise the cache"""
self._cache = {}
def get(self, object_path):
+ """Retrieve specified object from the cache
+
+ object_path -- full dbus path to the object
+
+ returns a presence.buddy.Buddy or presence.activity.Activity
+ instance or None if the object_path is not yet cached.
+
+ XXX could be written as return self._cache.get( object_path )
+ """
try:
return self._cache[object_path]
except KeyError:
return None
def add(self, obj):
+ """Adds given presence object to the cache
+
+ obj -- presence Buddy or Activity representation, the object's
+ object_path() method is used as the key for storage
+
+ returns None
+
+ XXX should raise an error on collisions, shouldn't it? or
+ return True/False to say whether the item was actually
+ added
+ """
op = obj.object_path()
if not self._cache.has_key(op):
self._cache[op] = obj
def remove(self, object_path):
+ """Remove the given presence object from the cache
+
+ object_path -- full dbus path to the object
+
+ returns None
+
+ XXX does two checks instead of one with a try:except for the
+ keyerror, normal case of deleting existing penalised as
+ a result.
+
+ try:
+ return self._cache.pop( key )
+ except KeyError:
+ return None
+ """
if self._cache.has_key(object_path):
del self._cache[object_path]
@@ -46,7 +101,13 @@ DBUS_PATH = "/org/laptop/Sugar/Presence"
class PresenceService(gobject.GObject):
-
+ """UI-side interface to the dbus presence service
+
+ This class provides UI programmers with simplified access
+ to the dbus service of the same name. It allows for observing
+ various events from the presence service as GObject events,
+ as well as some basic introspection queries.
+ """
__gsignals__ = {
'buddy-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT])),
@@ -71,6 +132,7 @@ class PresenceService(gobject.GObject):
def __init__(self):
+ """Initialise the service and connect to events"""
gobject.GObject.__init__(self)
self._objcache = ObjectCache()
self._bus = dbus.SessionBus()
@@ -84,6 +146,17 @@ class PresenceService(gobject.GObject):
self._ps.connect_to_signal('PrivateInvitation', self._private_invitation_cb)
def _new_object(self, object_path):
+ """Turn new object path into (cached) Buddy/Activity instance
+
+ object_path -- full dbus path of the new object, must be
+ prefixed with either of _PS_BUDDY_OP or _PS_ACTIVITY_OP
+
+ Note that this method is called throughout the class whenever
+ the representation of the object is required, it is not only
+ called when the object is first discovered.
+
+ returns presence Buddy or Activity representation
+ """
obj = self._objcache.get(object_path)
if not obj:
if object_path.startswith(self._PS_BUDDY_OP):
@@ -102,52 +175,79 @@ class PresenceService(gobject.GObject):
pass
def _emit_buddy_appeared_signal(self, object_path):
+ """Emit GObject event with presence.buddy.Buddy object"""
self.emit('buddy-appeared', self._new_object(object_path))
return False
def _buddy_appeared_cb(self, op):
+ """Callback for dbus event (forwards to method to emit GObject event)"""
gobject.idle_add(self._emit_buddy_appeared_signal, op)
def _emit_buddy_disappeared_signal(self, object_path):
+ """Emit GObject event with presence.buddy.Buddy object"""
self.emit('buddy-disappeared', self._new_object(object_path))
return False
def _buddy_disappeared_cb(self, object_path):
+ """Callback for dbus event (forwards to method to emit GObject event)"""
gobject.idle_add(self._emit_buddy_disappeared_signal, object_path)
def _emit_activity_invitation_signal(self, object_path):
+ """Emit GObject event with presence.activity.Activity object"""
self.emit('activity-invitation', self._new_object(object_path))
return False
def _activity_invitation_cb(self, object_path):
+ """Callback for dbus event (forwards to method to emit GObject event)"""
gobject.idle_add(self._emit_activity_invitation_signal, object_path)
def _emit_private_invitation_signal(self, bus_name, connection, channel):
+ """Emit GObject event with bus_name, connection and channel
+
+ XXX This seems to generate the wrong GObject event? It generates
+ 'service-disappeared' instead of private-invitation for some
+ reason. That event doesn't even seem to be registered?
+ """
self.emit('service-disappeared', bus_name, connection, channel)
return False
def _private_invitation_cb(self, bus_name, connection, channel):
+ """Callback for dbus event (forwards to method to emit GObject event)"""
gobject.idle_add(self._emit_service_disappeared_signal, bus_name,
connection, channel)
def _emit_activity_appeared_signal(self, object_path):
+ """Emit GObject event with presence.activity.Activity object"""
self.emit('activity-appeared', self._new_object(object_path))
return False
def _activity_appeared_cb(self, object_path):
+ """Callback for dbus event (forwards to method to emit GObject event)"""
gobject.idle_add(self._emit_activity_appeared_signal, object_path)
def _emit_activity_disappeared_signal(self, object_path):
+ """Emit GObject event with presence.activity.Activity object"""
self.emit('activity-disappeared', self._new_object(object_path))
return False
def _activity_disappeared_cb(self, object_path):
+ """Callback for dbus event (forwards to method to emit GObject event)"""
gobject.idle_add(self._emit_activity_disappeared_signal, object_path)
def get(self, object_path):
+ """Retrieve given object path as a Buddy/Activity object
+
+ XXX This is basically just an alias for _new_object, i.e. it
+ just adds an extra function-call to the operation.
+ """
return self._new_object(object_path)
def get_activities(self):
+ """Retrieve set of all activities from service
+
+ returns list of Activity objects for all object paths
+ the service reports exist (using GetActivities)
+ """
resp = self._ps.GetActivities()
acts = []
for item in resp:
@@ -155,6 +255,13 @@ class PresenceService(gobject.GObject):
return acts
def get_activity(self, activity_id):
+ """Retrieve single Activity object for the given unique id
+
+ activity_id -- unique ID for the activity
+
+ returns single Activity object or None if the activity
+ is not found using GetActivityById on the service
+ """
try:
act_op = self._ps.GetActivityById(activity_id)
except dbus.exceptions.DBusException:
@@ -162,6 +269,11 @@ class PresenceService(gobject.GObject):
return self._new_object(act_op)
def get_buddies(self):
+ """Retrieve set of all buddies from service
+
+ returns list of Buddy objects for all object paths
+ the service reports exist (using GetBuddies)
+ """
resp = self._ps.GetBuddies()
buddies = []
for item in resp:
@@ -169,6 +281,14 @@ class PresenceService(gobject.GObject):
return buddies
def get_buddy(self, key):
+ """Retrieve single Buddy object for the given public key
+
+ key -- buddy's public encryption key
+
+ returns single Buddy object or None if the activity
+ is not found using GetBuddyByPublicKey on the
+ service
+ """
try:
buddy_op = self._ps.GetBuddyByPublicKey(dbus.ByteArray(key))
except dbus.exceptions.DBusException:
@@ -176,6 +296,12 @@ class PresenceService(gobject.GObject):
return self._new_object(buddy_op)
def get_owner(self):
+ """Retrieves "owner" as a Buddy
+
+ XXX check that it really is a Buddy that's produced, what is
+ this the owner of? Shouldn't it be getting an activity
+ and then asking who the owner of that is?
+ """
try:
owner_op = self._ps.GetOwner()
except dbus.exceptions.DBusException:
@@ -183,13 +309,27 @@ class PresenceService(gobject.GObject):
return self._new_object(owner_op)
def _share_activity_cb(self, activity, op):
+ """Notify with GObject event of successful sharing of activity"""
self.emit("activity-shared", True, self._new_object(op), None)
def _share_activity_error_cb(self, activity, err):
+ """Notify with GObject event of unsuccessful sharing of activity"""
logging.debug("Error sharing activity %s: %s" % (activity.get_id(), err))
self.emit("activity-shared", False, None, err)
def share_activity(self, activity, properties={}):
+ """Ask presence service to ask the activity to share itself
+
+ Uses the ShareActivity method on the service to ask for the
+ sharing of the given activity. Arranges to emit activity-shared
+ event with:
+
+ (success, Activity, err)
+
+ on success/failure.
+
+ returns None
+ """
actid = activity.get_id()
atype = activity.get_service_name()
name = activity.props.title
@@ -199,6 +339,10 @@ class PresenceService(gobject.GObject):
class _MockPresenceService(gobject.GObject):
+ """Test fixture allowing testing of items that use PresenceService
+
+ See PresenceService for usage and purpose
+ """
__gsignals__ = {
'buddy-appeared': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
([gobject.TYPE_PYOBJECT])),
@@ -238,6 +382,7 @@ class _MockPresenceService(gobject.GObject):
_ps = None
def get_instance():
+ """Retrieve this process' view of the PresenceService"""
global _ps
if not _ps:
_ps = PresenceService()