← Back to team overview

gtg team mailing list archive

[Merge] lp:~nimit-svnit/gtg/backends-cleanup into lp:gtg

 

Nimit Shah has proposed merging lp:~nimit-svnit/gtg/backends-cleanup into lp:gtg.

Requested reviews:
  Gtg developers (gtg)

For more details, see:
https://code.launchpad.net/~nimit-svnit/gtg/backends-cleanup/+merge/141102

Pep8ification of Backends. RTM and Tweepy libraries which are to be updated later are not pep8ified
-- 
https://code.launchpad.net/~nimit-svnit/gtg/backends-cleanup/+merge/141102
Your team Gtg developers is requested to review the proposed merge of lp:~nimit-svnit/gtg/backends-cleanup into lp:gtg.
=== modified file 'GTG/backends/__init__.py'
--- GTG/backends/__init__.py	2012-11-25 19:19:44 +0000
+++ GTG/backends/__init__.py	2012-12-21 16:50:32 +0000
@@ -17,7 +17,6 @@
 # this program.  If not, see <http://www.gnu.org/licenses/>.
 # -----------------------------------------------------------------------------
 
-
 """
 Backends are a way to permanently store a project on a medium
 (like on the hard disk or on the internet)
@@ -36,7 +35,6 @@
 from GTG.core                    import CoreConfig
 
 
-
 class BackendFactory(Borg):
     '''
     This class holds the information about the backend types.
@@ -61,10 +59,10 @@
         #Look for backends in the GTG/backends dir
         this_dir = os.path.dirname(__file__)
         backend_files = filter(lambda f: f.endswith(".py") and     \
-               f[ : len(self.BACKEND_PREFIX)] == self.BACKEND_PREFIX , \
+               f[: len(self.BACKEND_PREFIX)] == self.BACKEND_PREFIX, \
                os.listdir(this_dir))
         #Create module names
-        module_names = map(lambda f: f.replace(".py",""), backend_files)
+        module_names = map(lambda f: f.replace(".py", ""), backend_files)
         Log.debug("Backends found: " + str(module_names))
         #Load backend modules
         for module_name in module_names:
@@ -87,7 +85,7 @@
 
     def get_backend(self, backend_name):
         '''
-        Returns the backend module for the backend matching 
+        Returns the backend module for the backend matching
         backend_name. Else, returns none
         '''
         if backend_name in self.backend_modules:
@@ -128,7 +126,7 @@
     def restore_backend_from_xml(self, dic):
         '''
         Function restoring a backend from its xml description.
-        dic should be a dictionary containing at least the key 
+        dic should be a dictionary containing at least the key
             - "module", with the module name
             - "xmlobject", with its xml description.
         Every other key is passed as-is to the backend, as parameter.
@@ -136,11 +134,11 @@
         Returns the backend instance, or None is something goes wrong
         '''
         if not "module" in dic or not "xmlobject" in dic:
-            Log.debug ("Malformed backend configuration found! %s" % \
+            Log.debug("Malformed backend configuration found! %s" % \
                        dic)
         module = self.get_backend(dic["module"])
         if module == None:
-            Log.debug ("could not load module for backend %s" % \
+            Log.debug("could not load module for backend %s" % \
                        dic["module"])
             return None
         #we pop the xml object, as it will be redundant when the parameters
@@ -171,7 +169,7 @@
                 dic["pid"] = str(uuid.uuid4())
                 dic["need_conversion"] = \
                     dic["xmlobject"].getAttribute("filename")
-                
+
         #Now that the backend list is build, we will construct them
         for dic in backends_dic:
             self.restore_backend_from_xml(dic)
@@ -186,14 +184,15 @@
 
     def _read_backend_configuration_file(self):
         '''
-        Reads the file describing the current backend configuration (project.xml)
-        and returns a list of dictionaries, each containing: 
+        Reads the file describing the current backend configuration
+        (project.xml) and returns a list of dictionaries, each containing:
          - the xml object defining the backend characteristics under
               "xmlobject"
          - the name of the backend under "module"
         '''
         # Read configuration file, if it does not exist, create one
-        datafile = os.path.join(CoreConfig().get_data_dir(), CoreConfig.DATA_FILE)
+        datafile = os.path.join(CoreConfig().get_data_dir(),
+                                                      CoreConfig.DATA_FILE)
         doc, configxml = cleanxml.openxmlfile(datafile, "config")
         xmlproject = doc.getElementsByTagName("backend")
         # collect configured backends

=== modified file 'GTG/backends/backend_evolution.py'
--- GTG/backends/backend_evolution.py	2012-11-25 19:19:44 +0000
+++ GTG/backends/backend_evolution.py	2012-12-21 16:50:32 +0000
@@ -40,22 +40,21 @@
 
 #Dictionaries to translate GTG tasks in Evolution ones
 _GTG_TO_EVOLUTION_STATUS = \
-        {Task.STA_ACTIVE:    evolution.ecal.ICAL_STATUS_CONFIRMED,
-         Task.STA_DONE:      evolution.ecal.ICAL_STATUS_COMPLETED,
+        {Task.STA_ACTIVE: evolution.ecal.ICAL_STATUS_CONFIRMED,
+         Task.STA_DONE: evolution.ecal.ICAL_STATUS_COMPLETED,
          Task.STA_DISMISSED: evolution.ecal.ICAL_STATUS_CANCELLED}
 
 _EVOLUTION_TO_GTG_STATUS = \
-        {evolution.ecal.ICAL_STATUS_CONFIRMED:   Task.STA_ACTIVE,
-         evolution.ecal.ICAL_STATUS_DRAFT:       Task.STA_ACTIVE,
-         evolution.ecal.ICAL_STATUS_FINAL:       Task.STA_ACTIVE,
-         evolution.ecal.ICAL_STATUS_INPROCESS:   Task.STA_ACTIVE,
+        {evolution.ecal.ICAL_STATUS_CONFIRMED: Task.STA_ACTIVE,
+         evolution.ecal.ICAL_STATUS_DRAFT: Task.STA_ACTIVE,
+         evolution.ecal.ICAL_STATUS_FINAL: Task.STA_ACTIVE,
+         evolution.ecal.ICAL_STATUS_INPROCESS: Task.STA_ACTIVE,
          evolution.ecal.ICAL_STATUS_NEEDSACTION: Task.STA_ACTIVE,
-         evolution.ecal.ICAL_STATUS_NONE:        Task.STA_ACTIVE,
-         evolution.ecal.ICAL_STATUS_TENTATIVE:   Task.STA_ACTIVE,
-         evolution.ecal.ICAL_STATUS_X:           Task.STA_ACTIVE,
-         evolution.ecal.ICAL_STATUS_COMPLETED:   Task.STA_DONE,
-         evolution.ecal.ICAL_STATUS_CANCELLED:   Task.STA_DISMISSED}
-
+         evolution.ecal.ICAL_STATUS_NONE: Task.STA_ACTIVE,
+         evolution.ecal.ICAL_STATUS_TENTATIVE: Task.STA_ACTIVE,
+         evolution.ecal.ICAL_STATUS_X: Task.STA_ACTIVE,
+         evolution.ecal.ICAL_STATUS_COMPLETED: Task.STA_DONE,
+         evolution.ecal.ICAL_STATUS_CANCELLED: Task.STA_DISMISSED}
 
 
 class Backend(PeriodicImportBackend):
@@ -65,10 +64,10 @@
 
 
     _general_description = { \
-        GenericBackend.BACKEND_NAME:       "backend_evolution", \
+        GenericBackend.BACKEND_NAME: "backend_evolution", \
         GenericBackend.BACKEND_HUMAN_NAME: _("Evolution tasks"), \
-        GenericBackend.BACKEND_AUTHORS:    ["Luca Invernizzi"], \
-        GenericBackend.BACKEND_TYPE:       GenericBackend.TYPE_READWRITE, \
+        GenericBackend.BACKEND_AUTHORS: ["Luca Invernizzi"], \
+        GenericBackend.BACKEND_TYPE: GenericBackend.TYPE_READWRITE, \
         GenericBackend.BACKEND_DESCRIPTION: \
             _("Lets you synchronize your GTG tasks with Evolution tasks"),\
         }
@@ -85,7 +84,6 @@
 ###############################################################################
 ### Backend standard methods ##################################################
 ###############################################################################
-
     def __init__(self, parameters):
         '''
         See GenericBackend for an explanation of this function.
@@ -112,8 +110,8 @@
                for task in self._evolution_tasks.get_all_objects()])
         #If it's the very first time the backend is run, it's possible that the
         # user already synced his tasks in some way (but we don't know that).
-        # Therefore, we attempt to induce those tasks relationships matching the
-        # titles.
+        # Therefore, we attempt to induce those tasks relationships matching
+        # the titles.
         if self._parameters["is-first-run"]:
             gtg_titles_dic = {}
             for tid in self.datastore.get_all_tasks():
@@ -121,7 +119,7 @@
                 if not self._gtg_task_is_syncable_per_attached_tags(gtg_task):
                     continue
                 gtg_title = gtg_task.get_title()
-                if gtg_titles_dic.has_key(gtg_title):
+                if gtg_title in gtg_titles_dic:
                     gtg_titles_dic[gtg_task.get_title()].append(tid)
                 else:
                     gtg_titles_dic[gtg_task.get_title()] = [tid]
@@ -171,7 +169,6 @@
 ###############################################################################
 ### Process tasks #############################################################
 ###############################################################################
-
     @interruptible
     def remove_task(self, tid):
         '''
@@ -214,7 +211,8 @@
                                 self._evo_get_modified(evo_task),
                                 "GTG")
                 self.sync_engine.record_relationship( \
-                    local_id = tid, remote_id = evo_task.get_uid(), meme = meme)
+                    local_id = tid, remote_id = evo_task.get_uid(),
+                                                        meme = meme)
 
         elif action == SyncEngine.UPDATE:
             with self.datastore.get_backend_mutex():
@@ -299,7 +297,6 @@
 ###############################################################################
 ### Helper methods ############################################################
 ###############################################################################
-
     def _evo_has_task(self, evo_task_id):
         '''Returns true if Evolution has that task'''
         return bool(self._evo_get_task(evo_task_id))
@@ -408,7 +405,8 @@
         #GTG thinks in local time, evolution in utc
         #to convert date objects between different timezones, we must convert
         #them to datetime objects
-        gtg_datetime = datetime.datetime.combine(gtg_date.to_py_date(), datetime.time(0))
+        gtg_datetime = datetime.datetime.combine(gtg_date.to_py_date(),
+                                                             datetime.time(0))
         #We don't want to express GTG date into a UTC equivalent. Instead, we
         #want the *same* date in GTG and evolution. Therefore, we must not do
         #the conversion Local-> UTC (which would point to the same moment in

=== modified file 'GTG/backends/backend_gnote.py'
--- GTG/backends/backend_gnote.py	2012-11-25 19:19:44 +0000
+++ GTG/backends/backend_gnote.py	2012-12-21 16:50:32 +0000
@@ -28,20 +28,19 @@
 from GTG.backends.generictomboy  import GenericTomboy
 
 
-
 class Backend(GenericTomboy):
     '''
     A simple class that adds some description to the GenericTomboy class.
     It's done this way since Tomboy and Gnote backends have different
     descriptions and Dbus addresses but the same backend behind them.
     '''
-    
+
 
     _general_description = { \
-        GenericBackend.BACKEND_NAME:       "backend_gnote", \
+        GenericBackend.BACKEND_NAME: "backend_gnote", \
         GenericBackend.BACKEND_HUMAN_NAME: _("Gnote"), \
-        GenericBackend.BACKEND_AUTHORS:    ["Luca Invernizzi"], \
-        GenericBackend.BACKEND_TYPE:       GenericBackend.TYPE_READWRITE, \
+        GenericBackend.BACKEND_AUTHORS: ["Luca Invernizzi"], \
+        GenericBackend.BACKEND_TYPE: GenericBackend.TYPE_READWRITE, \
         GenericBackend.BACKEND_DESCRIPTION: \
             _("This service can synchronize all or part of your Gnote"
               " notes in GTG. If you decide it would be handy to"

=== modified file 'GTG/backends/backend_identica.py'
--- GTG/backends/backend_identica.py	2012-11-25 19:19:44 +0000
+++ GTG/backends/backend_identica.py	2012-12-21 16:50:32 +0000
@@ -35,13 +35,12 @@
 from GTG.backends.syncengine            import SyncEngine
 from GTG.tools.logger                   import Log
 
-#The Ubuntu version of python twitter is not updated: 
+#The Ubuntu version of python twitter is not updated:
 # it does not have identi.ca support. Meanwhile, we ship the right version
 # with our code.
 import GTG.backends.twitter as twitter
 
 
-
 class Backend(PeriodicImportBackend):
     '''
     Identi.ca backend: imports direct messages, replies and/or the user
@@ -52,8 +51,8 @@
     _general_description = { \
         GenericBackend.BACKEND_NAME: "backend_identica", \
         GenericBackend.BACKEND_HUMAN_NAME: _("Identi.ca"), \
-        GenericBackend.BACKEND_AUTHORS:    ["Luca Invernizzi"], \
-        GenericBackend.BACKEND_TYPE:       GenericBackend.TYPE_IMPORT, \
+        GenericBackend.BACKEND_AUTHORS: ["Luca Invernizzi"], \
+        GenericBackend.BACKEND_TYPE: GenericBackend.TYPE_IMPORT, \
         GenericBackend.BACKEND_DESCRIPTION: \
             _("Imports your identi.ca  messages into your GTG " + \
               "tasks. You can choose to either import all your " + \
@@ -101,7 +100,7 @@
                                      self.get_id())
         self.sync_engine = self._load_pickled_file(self.data_path, \
                                                         SyncEngine())
-        
+
     def save_state(self):
         '''
         See GenericBackend for an explanation of this function.
@@ -152,7 +151,7 @@
                                         lambda tweet_id: True, \
                                         is_syncable)
         Log.debug("processing tweet (%s, %s)" % (action, is_syncable))
-        
+
         self.cancellation_point()
         if action == None or action == SyncEngine.UPDATE:
             return
@@ -185,8 +184,8 @@
             task.add_tag("@" + message.GetSenderScreenName())
         except:
             pass
-        text = message.GetText()    
-        
+        text = message.GetText()
+
         #convert #hastags to @tags
         matches = re.finditer("(?<![^|\s])(#\w+)", text)
         for g in matches:
@@ -227,7 +226,6 @@
 ###############################################################################
 ### AUTHENTICATION ############################################################
 ###############################################################################
-
     class controlled_execution(object):
         '''
         This class performs the login to identica and execute the appropriate
@@ -277,4 +275,3 @@
         def signal_network_down(self):
             BackendSignals().backend_failed(self.backend.get_id(), \
                             BackendSignals.ERRNO_NETWORK)
-

=== modified file 'GTG/backends/backend_launchpad.py'
--- GTG/backends/backend_launchpad.py	2012-11-25 19:19:44 +0000
+++ GTG/backends/backend_launchpad.py	2012-12-21 16:50:32 +0000
@@ -46,20 +46,20 @@
 
 class Backend(PeriodicImportBackend):
     '''Launchpad backend, capable of importing launchpad bugs in GTG.'''
-    
+
 
     _general_description = { \
-        GenericBackend.BACKEND_NAME:       "backend_launchpad", \
+        GenericBackend.BACKEND_NAME: "backend_launchpad", \
         GenericBackend.BACKEND_HUMAN_NAME: _("Launchpad"), \
-        GenericBackend.BACKEND_AUTHORS:    ["Luca Invernizzi"], \
-        GenericBackend.BACKEND_TYPE:       GenericBackend.TYPE_READONLY, \
+        GenericBackend.BACKEND_AUTHORS: ["Luca Invernizzi"], \
+        GenericBackend.BACKEND_TYPE: GenericBackend.TYPE_READONLY, \
         GenericBackend.BACKEND_DESCRIPTION: \
-            _("This synchronization service lets you import the bugs assigned to "
-              "you (or someone else) on Launchpad in GTG. As the"
+            _("This synchronization service lets you import the bugs assigned"
+              " to you (or someone else) on Launchpad in GTG. As the"
               " bug state changes in Launchpad, the GTG task is "
               " updated.\n"
-              "Please note that this is a read only synchronization service, which "
-              "means that if you open one of the imported tasks and "
+              "Please note that this is a read only synchronization service,"
+              " which means that if you open one of the imported tasks and "
               " change one of the:\n"
               "  - title\n"
               "  - description\n"
@@ -89,7 +89,6 @@
 ###############################################################################
 ### Backend standard methods ##################################################
 ###############################################################################
-
     def __init__(self, parameters):
         '''
         See GenericBackend for an explanation of this function.
@@ -114,8 +113,8 @@
         # bug to multiple projects: you have one bug and several bug tasks).
         # At least, one bug contains a bug task (if it's referring to a single
         # project).
-        # Here, we process bug tasks, since those are the ones that get assigned
-        # to someone.
+        # Here, we process bug tasks, since those are the ones that get
+        # assigned to someone.
         # To avoid having multiple GTG Tasks for the same bug (because we use
         # bug tasks, this may happen if somebody is working at the same bug for
         # different projects), we use the bug self_link for indexing the tasks.
@@ -137,7 +136,7 @@
             BackendSignals().backend_failed(self.get_id(), \
                             BackendSignals.ERRNO_NETWORK)
             return
-        #Getting the user data 
+        #Getting the user data
         try:
             self.cancellation_point()
             me = self.launchpad.people[self._parameters["username"]]
@@ -182,10 +181,9 @@
 ###############################################################################
 ### Process tasks #############################################################
 ###############################################################################
-
     def _process_launchpad_bug(self, bug):
         '''
-        Given a bug object, finds out if it must be synced to a GTG note and, 
+        Given a bug object, finds out if it must be synced to a GTG note and,
         if so, it carries out the synchronization (by creating or
         updating a GTG task, or deleting itself if the related task has
         been deleted)
@@ -278,8 +276,8 @@
         '''
         We fetch all the necessary info that we need from the bug to populate a
         task beforehand (these will be used in _populate_task).
-        This function takes a long time to complete (all access to bug data are 
-        requests on then net), but it can crash without having the state of the 
+        This function takes a long time to complete (all access to bug data are
+        requests on then net), but it can crash without having the state of the
         related task half-changed.
 
         @param bug: a launchpad bug task
@@ -295,9 +293,11 @@
                    'self_link': self_link,
                    'modified': self._get_bug_modified_datetime(bug),
                    'owner': owner.display_name,
-                   'completed': bug_task.status in ["Fix Committed", "Fix Released"],
+                   'completed': bug_task.status in ["Fix Committed",
+                                                              "Fix Released"],
                    'owner_karma': owner.karma}
-        bug_dic['number'] = bug_dic['self_link'][bug_dic['self_link'].rindex("/") + 1 :]
+        bug_dic['number'] = bug_dic['self_link']\
+                                      [bug_dic['self_link'].rindex("/") + 1:]
         #find the projects target of the bug
         projects = []
         for task in bug.bug_tasks:
@@ -308,12 +308,12 @@
             except AttributeError:
                 #bug task is not assigned to anyone
                 continue
-            a_sl[a_sl.index("~") + 1 :]
-            if a_sl[a_sl.index("~") + 1 :] == self._parameters["username"]:
+            a_sl[a_sl.index("~") + 1:]
+            if a_sl[a_sl.index("~") + 1:] == self._parameters["username"]:
                 t_sl = task.target.self_link
                 projects.append(
-                    {"project_short": t_sl[t_sl.rindex("/") + 1 :],
-                     "project_long":  task.bug_target_display_name,})
+                    {"project_short": t_sl[t_sl.rindex("/") + 1:],
+                     "project_long": task.bug_target_display_name, })
         bug_dic["projects"] = projects
         return bug_dic
 
@@ -326,9 +326,8 @@
         projects = [dic['project_short'] for dic in bug_dic['projects']]
         #one link is enough, since they're all alias
         bug_project = bug_dic['projects'][0]['project_short']
-        text += _("Link to bug: " ) + \
+        text += _("Link to bug: ") + \
                 "https://bugs.edge.launchpad.net/%s/+bug/%s"; % \
                 (bug_project, bug_dic["number"]) + '\n'
         text += '\n' + bug_dic["text"]
         return text
-

=== modified file 'GTG/backends/backend_localfile.py'
--- GTG/backends/backend_localfile.py	2012-11-25 19:19:44 +0000
+++ GTG/backends/backend_localfile.py	2012-12-21 16:50:32 +0000
@@ -37,31 +37,32 @@
 # Ignore all other elements but this one
 TASK_NODE = "task"
 
+
 class Backend(GenericBackend):
     """
     Localfile backend, which stores your tasks in a XML file in the standard
     XDG_DATA_DIR/gtg folder (the path is configurable).
     An instance of this class is used as the default backend for GTG.
-    This backend loads all the tasks stored in the localfile after it's enabled,
+    This backend loads all the tasks stored in the localfile after it's enabled
     and from that point on just writes the changes to the file: it does not
     listen for eventual file changes
     """
-    
+
     # default path for filenames
-    DEFAULT_PATH = CoreConfig().get_data_dir() 
+    DEFAULT_PATH = CoreConfig().get_data_dir()
 
-    # General description of the backend: these are used to show a description of
-    # the backend to the user when s/he is considering adding it.
+    # General description of the backend: these are used to show a description
+    # of the backend to the user when s/he is considering adding it.
     # BACKEND_NAME is the name of the backend used internally (it must be
     # unique).
     # Please note that BACKEND_NAME and BACKEND_ICON_NAME should *not* be
     # translated.
     _general_description = {
-        GenericBackend.BACKEND_NAME:       "backend_localfile",
+        GenericBackend.BACKEND_NAME: "backend_localfile",
         GenericBackend.BACKEND_HUMAN_NAME: _("Local File"),
-        GenericBackend.BACKEND_AUTHORS:    ["Lionel Dricot",
+        GenericBackend.BACKEND_AUTHORS: ["Lionel Dricot",
                                             "Luca Invernizzi"],
-        GenericBackend.BACKEND_TYPE:       GenericBackend.TYPE_READWRITE,
+        GenericBackend.BACKEND_TYPE: GenericBackend.TYPE_READWRITE,
         GenericBackend.BACKEND_DESCRIPTION:
             _("Your tasks are saved in a text file (XML format). " +
               " This is the most basic and the default way " +
@@ -72,16 +73,16 @@
     # parameter has a name, a type and a default value.
     # Here, we define a parameter "path", which is a string, and has a default
     # value as a random file in the default path
-    # NOTE: to keep this simple, the filename default path is the same until GTG
-    #      is restarted. I consider this a minor annoyance, and we can avoid
-    #      coding the change of the path each time a backend is
+    # NOTE: to keep this simple, the filename default path is the same until
+    #      GTG is restarted. I consider this a minor annoyance, and we can
+    #      avoid coding the change of the path each time a backend is
     #      created (invernizzi)
     _static_parameters = {
         "path": {
             GenericBackend.PARAM_TYPE: GenericBackend.TYPE_STRING,
             GenericBackend.PARAM_DEFAULT_VALUE:
-                 os.path.join(DEFAULT_PATH, "gtg_tasks-%s.xml" %(uuid.uuid4()))
-    }}
+                 os.path.join(DEFAULT_PATH, "gtg_tasks-%s.xml" %\
+                 (uuid.uuid4()))}}
 
     def __init__(self, parameters):
         """
@@ -90,7 +91,7 @@
         @param parameters: A dictionary of parameters, generated from
         _static_parameters. A few parameters are added to those, the list of
         these is in the "DefaultBackend" class, look for the KEY_* constants.
-    
+
         The backend should take care if one expected value is None or
         does not exist in the dictionary.
         """
@@ -105,7 +106,7 @@
         if not self.KEY_DEFAULT_BACKEND in parameters:
             parameters[self.KEY_DEFAULT_BACKEND] = True
         ####
-        
+
         self.doc, self.xmlproj = cleanxml.openxmlfile( \
                                 self._parameters["path"], "project")
         # Make safety daily backup after loading
@@ -131,9 +132,9 @@
                         self._parameters["path"], "project")
 
     def start_get_tasks(self):
-        """ This function starts submitting the tasks from the XML file into GTG core.
-        It's run as a separate thread.
-                
+        """ This function starts submitting the tasks from the XML file into
+        GTG core. It's run as a separate thread.
+
         @return: start_get_tasks() might not return or finish
         """
         for node in self.xmlproj.childNodes:
@@ -178,13 +179,13 @@
             modified = True
 
         #if the XML object has changed, we save it to file
-        if modified and self._parameters["path"] and self.doc :
+        if modified and self._parameters["path"] and self.doc:
             cleanxml.savexml(self._parameters["path"], self.doc)
 
     def remove_task(self, tid):
         """ This function is called from GTG core whenever a task must be
         removed from the backend. Note that the task could be not present here.
-        
+
         @param tid: the id of the task to delete
         """
         modified = False

=== modified file 'GTG/backends/backend_mantis.py'
--- GTG/backends/backend_mantis.py	2012-11-25 19:19:44 +0000
+++ GTG/backends/backend_mantis.py	2012-12-21 16:50:32 +0000
@@ -36,19 +36,21 @@
 Dependencies:
   * python-suds
 '''
+
+
 class Backend(PeriodicImportBackend):
     _general_description = { \
-        GenericBackend.BACKEND_NAME:       "backend_mantis", \
+        GenericBackend.BACKEND_NAME: "backend_mantis", \
         GenericBackend.BACKEND_HUMAN_NAME: _("MantisBT"), \
-        GenericBackend.BACKEND_AUTHORS:    ["Luca Invernizzi", "Alayn Gortazar"], \
-        GenericBackend.BACKEND_TYPE:       GenericBackend.TYPE_READONLY, \
+        GenericBackend.BACKEND_AUTHORS: ["Luca Invernizzi", "Alayn Gortazar"],\
+        GenericBackend.BACKEND_TYPE: GenericBackend.TYPE_READONLY, \
         GenericBackend.BACKEND_DESCRIPTION: \
-            _("This synchronization service lets you import the issues found on Mantis" 
-              " using a prestablished filter called 'gtg'."
+            _("This synchronization service lets you import the issues found"
+              " on Mantis using a prestablished filter called 'gtg'."
               " As the issue state changes in Mantis, the GTG task is "
               " updated.\n"
-              "Please note that this is a read only synchronization service, which "
-              "means that if you open one of the imported tasks and "
+              "Please note that this is a read only synchronization service,"
+              " which means that if you open one of the imported tasks and "
               " change one of the:\n"
               "  - title\n"
               "  - description\n"
@@ -59,8 +61,8 @@
               " changes will be preserved. This is useful to add "
               " personal annotations to issue"), \
         }
- 
-    
+
+
     _static_parameters = {\
         "period": { \
             GenericBackend.PARAM_TYPE: GenericBackend.TYPE_INT, \
@@ -73,12 +75,13 @@
             GenericBackend.PARAM_DEFAULT_VALUE: '', }, \
         "service-url": { \
             GenericBackend.PARAM_TYPE: GenericBackend.TYPE_STRING, \
-            GenericBackend.PARAM_DEFAULT_VALUE: 'http://example.com/mantis', }, \
+            GenericBackend.PARAM_DEFAULT_VALUE: 'http://example.com/mantis',
+                                                                        }, \
         "tag-with-project-name": { \
             GenericBackend.PARAM_TYPE: GenericBackend.TYPE_BOOL, \
             GenericBackend.PARAM_DEFAULT_VALUE: True}, \
        }
-    
+
     def __init__(self, parameters):
         '''
         See GenericBackend for an explanation of this function.
@@ -89,16 +92,18 @@
         self.data_path = os.path.join('backends/mantis/', \
                                       "sync_engine-" + self.get_id())
         self.sync_engine = self._load_pickled_file(self.data_path, \
-                                                   SyncEngine())    
+                                                   SyncEngine())
+
     def save_state(self):
         '''Saves the state of the synchronization'''
         self._store_pickled_file(self.data_path, self.sync_engine)
 
     def do_periodic_import(self):
-        #Establishing connection 
+        #Establishing connection
         try:
             self.cancellation_point()
-            client = Client('%s/api/soap/mantisconnect.php?wsdl' % (self._parameters['service-url']))
+            client = Client('%s/api/soap/mantisconnect.php?wsdl' % \
+                                            (self._parameters['service-url']))
         except KeyError:
             self.quit(disable = True)
             BackendSignals().backend_failed(self.get_id(), \
@@ -106,8 +111,11 @@
             return
 
 
-        projects = client.service.mc_projects_get_user_accessible(self._parameters['username'], self._parameters['password'])
-        filters = client.service.mc_filter_get(self._parameters['username'], self._parameters['password'], 0)
+        projects = client.service.mc_projects_get_user_accessible(
+                                        self._parameters['username'],
+                                        self._parameters['password'])
+        filters = client.service.mc_filter_get(self._parameters['username'],
+                                             self._parameters['password'], 0)
 
         #Fetching the issues
         self.cancellation_point()
@@ -115,7 +123,11 @@
         for filt in filters:
             if filt['name'] == 'gtg':
                 for project in projects:
-                    my_issues = client.service.mc_filter_get_issues(self._parameters['username'], self._parameters['password'], project['id'], filt['id'], 0, 100)
+                    my_issues = client.service.mc_filter_get_issues(
+                                                 self._parameters['username'],
+                                                 self._parameters['password'],
+                                                 project['id'],
+                                                 filt['id'], 0, 100)
                     for issue in my_issues:
                         self.cancellation_point()
                         self._process_mantis_issue(issue)
@@ -137,17 +149,16 @@
 ###############################################################################
 ### Process tasks #############################################################
 ###############################################################################
-
     def _process_mantis_issue(self, issue):
         '''
-        Given a issue object, finds out if it must be synced to a GTG note and, 
+        Given a issue object, finds out if it must be synced to a GTG note and,
         if so, it carries out the synchronization (by creating or
         updating a GTG task, or deleting itself if the related task has
         been deleted)
 
         @param note: a mantis issue
         '''
-        action, tid = self.sync_engine.analyze_remote_id(str(issue['id']), \
+        action, tid = self.sync_engine.analyze_remote_id(str(issue['id']),
                  self.datastore.has_task, lambda b: True)
         Log.debug("processing mantis (%s)" % (action))
 
@@ -165,18 +176,18 @@
                 tid = str(uuid.uuid4())
                 task = self.datastore.task_factory(tid)
                 self._populate_task(task, issue_dic)
-                self.sync_engine.record_relationship(local_id = tid,\
-                            remote_id = str(issue_dic['number']), \
-                            meme = SyncMeme(\
-                                        task.get_modified(), \
-                                        issue_dic['modified'], \
+                self.sync_engine.record_relationship(local_id = tid,
+                            remote_id = str(issue_dic['number']),
+                            meme = SyncMeme(
+                                        task.get_modified(),
+                                        issue_dic['modified'],
                                         self.get_id()))
                 self.datastore.push_task(task)
 
             elif action == SyncEngine.UPDATE:
                 task = self.datastore.get_task(tid)
                 self._populate_task(task, issue_dic)
-                meme = self.sync_engine.get_meme_from_remote_id( \
+                meme = self.sync_engine.get_meme_from_remote_id(
                                                     issue_dic['number'])
                 meme.set_local_last_modified(task.get_modified())
                 meme.set_remote_last_modified(issue_dic['modified'])
@@ -184,8 +195,8 @@
 
     def _prefetch_issue_data(self, mantis_issue):
         '''
-        We fetch all the necessary info that we need from the mantis_issue to populate a
-        task beforehand (these will be used in _populate_task).
+        We fetch all the necessary info that we need from the mantis_issue to
+        populate a task beforehand (these will be used in _populate_task).
 
         @param mantis_issue: a mantis issue
         @returns dict: a dictionary containing the relevant issue attributes
@@ -200,20 +211,20 @@
                    'number': str(mantis_issue['id'])}
 
         try:
-            issue_dic['assigned'] = mantis_issue['handler'].name == self._parameters['username']
+            issue_dic['assigned'] = mantis_issue['handler'].name == \
+                                             self._parameters['username']
         except AttributeError:
             issue_dic['assigned'] = False
-            
+
         return issue_dic
 
-
     def _populate_task(self, task, issue_dic):
         '''
         Fills a GTG task with the data from a mantis issue.
 
         @param task: a Task
         @param issue_dic: a mantis issue
-        
+
         '''
         #set task status
         if issue_dic["completed"]:
@@ -226,23 +237,23 @@
         text = self._build_issue_text(issue_dic)
         if task.get_excerpt() != text:
             task.set_text(text)
-            
+
         new_tags = set([])
         if self._parameters["tag-with-project-name"]:
-            new_tags = set(['@' + issue_dic['project']])        
+            new_tags = set(['@' + issue_dic['project']])
         current_tags = set(task.get_tags_name())
         #add the new ones
         for tag in new_tags.difference(current_tags):
             task.add_tag(tag)
-        
+
         task.add_remote_id(self.get_id(), issue_dic['number'])
 
     def _build_issue_text(self, issue_dic):
         '''
         Creates the text that describes a issue
         '''
-        text = _("Reported by: ") + issue_dic["reporter"] + '\n' 
-        text += _("Link to issue: " ) + \
+        text = _("Reported by: ") + issue_dic["reporter"] + '\n'
+        text += _("Link to issue: ") + \
                 self._parameters['service-url'] + '/view.php?id=%s' % \
                 (issue_dic["number"]) + '\n'
         text += '\n' + issue_dic["text"]

=== modified file 'GTG/backends/backend_tomboy.py'
--- GTG/backends/backend_tomboy.py	2012-11-25 19:19:44 +0000
+++ GTG/backends/backend_tomboy.py	2012-12-21 16:50:32 +0000
@@ -27,23 +27,22 @@
 from GTG.backends.generictomboy  import GenericTomboy
 
 
-
 class Backend(GenericTomboy):
     '''
     A simple class that adds some description to the GenericTomboy class.
     It's done this way since Tomboy and Gnote backends have different
     descriptions and Dbus addresses but the same backend behind them.
     '''
-    
+
 
     _general_description = { \
-        GenericBackend.BACKEND_NAME:       "backend_tomboy", \
+        GenericBackend.BACKEND_NAME: "backend_tomboy", \
         GenericBackend.BACKEND_HUMAN_NAME: _("Tomboy"), \
-        GenericBackend.BACKEND_AUTHORS:    ["Luca Invernizzi"], \
-        GenericBackend.BACKEND_TYPE:       GenericBackend.TYPE_READWRITE, \
+        GenericBackend.BACKEND_AUTHORS: ["Luca Invernizzi"], \
+        GenericBackend.BACKEND_TYPE: GenericBackend.TYPE_READWRITE, \
         GenericBackend.BACKEND_DESCRIPTION: \
-            _("This synchronization service can synchronize all or part of your Tomboy"
-              " notes in GTG. If you decide it would be handy to"
+            _("This synchronization service can synchronize all or part of"
+              " your Tomboy notes in GTG. If you decide it would be handy to"
               " have one of your notes in your TODO list, just tag it "
               "with the tag you have chosen (you'll configure it later"
               "), and it will appear in GTG."),\

=== modified file 'GTG/backends/backend_twitter.py'
--- GTG/backends/backend_twitter.py	2012-11-25 19:19:44 +0000
+++ GTG/backends/backend_twitter.py	2012-12-21 16:50:32 +0000
@@ -52,8 +52,8 @@
     _general_description = { \
         GenericBackend.BACKEND_NAME: "backend_twitter", \
         GenericBackend.BACKEND_HUMAN_NAME: _("Twitter"), \
-        GenericBackend.BACKEND_AUTHORS:    ["Luca Invernizzi"], \
-        GenericBackend.BACKEND_TYPE:       GenericBackend.TYPE_IMPORT, \
+        GenericBackend.BACKEND_AUTHORS: ["Luca Invernizzi"], \
+        GenericBackend.BACKEND_TYPE: GenericBackend.TYPE_IMPORT, \
         GenericBackend.BACKEND_DESCRIPTION: \
             _("Imports your twitter  messages into your GTG " + \
               "tasks. You can choose to either import all your " + \
@@ -81,10 +81,10 @@
             GenericBackend.PARAM_TYPE: GenericBackend.TYPE_BOOL, \
             GenericBackend.PARAM_DEFAULT_VALUE: True, },
         }
-    
+
     CONSUMER_KEY = "UDRov5YF3ZUinftvVBoeyA"
     #This is supposed to be secret (because of OAuth), but that's not possible.
-    #A xAuth alternative is possible, but it's enabled on mail request if the 
+    #A xAuth alternative is possible, but it's enabled on mail request if the
     # twitter staff considers your application worthy of such honour.
     CONSUMER_SECRET = "BApykCPskoZ0g4QpVS7yC7TrZntm87KruSeJwvqTg"
 
@@ -103,7 +103,7 @@
         self.auth_path = os.path.join('backends/twitter/', "auth-%s" %\
                                      self.get_id())
         self.auth_params = self._load_pickled_file(self.auth_path, None)
-        self.authenticated  = False
+        self.authenticated = False
         self.authenticating = False
 
     def save_state(self):
@@ -116,7 +116,6 @@
 ###############################################################################
 ### IMPORTING TWEETS ##########################################################
 ###############################################################################
-
     def do_periodic_import(self):
         '''
         See GenericBackend for an explanation of this function.
@@ -158,11 +157,11 @@
                                         lambda tweet_id: True, \
                                         is_syncable)
         Log.debug("processing tweet (%s, %s)" % (action, is_syncable))
-        
+
         self.cancellation_point()
         if action == None or action == SyncEngine.UPDATE:
             return
-        
+
         elif action == SyncEngine.ADD:
             tid = str(uuid.uuid4())
             task = self.datastore.task_factory(tid)
@@ -181,7 +180,6 @@
 
         self.save_state()
 
-
     def _populate_task(self, task, message):
         '''
         Given a twitter message and a GTG task, fills the task with the content
@@ -198,7 +196,7 @@
             task.add_tag("@" + user)
 
         #setting title, text and tags
-        text = message.text    
+        text = message.text
         #convert #hastags to @tags
         matches = re.finditer("(?<![^|\s])(#\w+)", text)
         for g in matches:
@@ -228,7 +226,7 @@
             tags = set(Backend._extract_tags_from_text(tweet.text))
             return tags.intersection(set(self._parameters["import-tags"])) \
                     != set()
-    
+
     @staticmethod
     def _extract_tags_from_text(text):
         '''
@@ -239,7 +237,6 @@
 ###############################################################################
 ### AUTHENTICATION ############################################################
 ###############################################################################
-
     def _start_authentication(self):
         '''
         Fist step of authentication: opening the browser with the oauth page
@@ -250,8 +247,8 @@
         #      However, twitter is moving to oauth only authentication, while
         #      identica uses standard login. For now, I'll keep the backends
         #      separate, using two different libraries (Invernizzi)
-                #auth = tweepy.BasicAuthHandler(username, password, 
-                #host ='identi.ca', api_root = '/api', 
+                #auth = tweepy.BasicAuthHandler(username, password,
+                #host ='identi.ca', api_root = '/api',
                 #secure=True)
         self.auth = tweepy.OAuthHandler(self.CONSUMER_KEY, \
                                         self.CONSUMER_SECRET)
@@ -303,7 +300,7 @@
             self.auth_params = (token.key, token.secret)
             self._store_pickled_file(self.auth_path, self.auth_params)
             self._end_authentication()
-    
+
     def _end_authentication(self):
         '''
         Last step of authentication. Creates the API objects and starts

=== modified file 'GTG/backends/backendsignals.py'
--- GTG/backends/backendsignals.py	2012-11-25 19:19:44 +0000
+++ GTG/backends/backendsignals.py	2012-12-21 16:50:32 +0000
@@ -22,15 +22,14 @@
 from GTG.tools.borg import Borg
 
 
-
 class BackendSignals(Borg):
     '''
-    This class handles the signals that involve backends. 
+    This class handles the signals that involve backends.
     In particular, it's a wrapper Borg class around a _BackendSignalsGObject
     class, and all method of the wrapped class can be used as if they were part
     of this class
     '''
-    
+
     #error codes to send along with the BACKEND_FAILED signal
     ERRNO_AUTHENTICATION = "authentication failed"
     ERRNO_NETWORK = "network is down"
@@ -63,7 +62,6 @@
     return (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, args)
 
 
-
 class _BackendSignalsGObject(gobject.GObject):
 
     #signal name constants
@@ -85,17 +83,17 @@
     INTERACTION_CONFIRM = 'confirm'
     INTERACTION_TEXT = 'text'
 
-    __gsignals__ = {BACKEND_STATE_TOGGLED : signal_type_factory(str), \
-                    BACKEND_RENAMED       : signal_type_factory(str), \
-                    BACKEND_ADDED         : signal_type_factory(str), \
-                    BACKEND_REMOVED       : signal_type_factory(str), \
-                    BACKEND_SYNC_STARTED  : signal_type_factory(str), \
-                    BACKEND_SYNC_ENDED    : signal_type_factory(str), \
+    __gsignals__ = {BACKEND_STATE_TOGGLED: signal_type_factory(str), \
+                    BACKEND_RENAMED: signal_type_factory(str), \
+                    BACKEND_ADDED: signal_type_factory(str), \
+                    BACKEND_REMOVED: signal_type_factory(str), \
+                    BACKEND_SYNC_STARTED: signal_type_factory(str), \
+                    BACKEND_SYNC_ENDED: signal_type_factory(str), \
                     DEFAULT_BACKEND_LOADED: signal_type_factory(), \
-                    BACKEND_FAILED        : signal_type_factory(str, str), \
-                    INTERACTION_REQUESTED : signal_type_factory(str, str, \
-                                                                str,  str)}
-    
+                    BACKEND_FAILED: signal_type_factory(str, str), \
+                    INTERACTION_REQUESTED: signal_type_factory(str, str, \
+                                                                str, str)}
+
     def __init__(self):
         super(_BackendSignalsGObject, self).__init__()
         self.backends_currently_syncing = []
@@ -104,7 +102,6 @@
     #connecting to signals is fine, but keep an eye if you should emit them.
     #As a general rule, signals should only be emitted in the GenericBackend
     #class
-    
     def _emit_signal(self, signal, backend_id):
         gobject.idle_add(self.emit, signal, backend_id)
 
@@ -124,13 +121,13 @@
         gobject.idle_add(self.emit, self.DEFAULT_BACKEND_LOADED)
 
     def backend_failed(self, backend_id, error_code):
-        gobject.idle_add(self.emit, self.BACKEND_FAILED, backend_id, \
+        gobject.idle_add(self.emit, self.BACKEND_FAILED, backend_id,
                          error_code)
 
-    def interaction_requested(self, backend_id, description, \
+    def interaction_requested(self, backend_id, description,
                               interaction_type, callback_str):
-        gobject.idle_add(self.emit, self.INTERACTION_REQUESTED, \
-                         backend_id, description, interaction_type, callback_str)
+        gobject.idle_add(self.emit, self.INTERACTION_REQUESTED,
+                      backend_id, description, interaction_type, callback_str)
 
     def backend_sync_started(self, backend_id):
         self._emit_signal(self.BACKEND_SYNC_STARTED, backend_id)
@@ -142,7 +139,6 @@
             self.backends_currently_syncing.remove(backend_id)
         except:
             pass
-    
+
     def is_backend_syncing(self, backend_id):
         return backend_id in self.backends_currently_syncing
-

=== modified file 'GTG/backends/genericbackend.py'
--- GTG/backends/genericbackend.py	2012-11-25 19:19:44 +0000
+++ GTG/backends/genericbackend.py	2012-12-21 16:50:32 +0000
@@ -88,8 +88,8 @@
         '''
         Called each time it is enabled (including on backend creation).
         Please note that a class instance for each disabled backend *is*
-        created, but it's not initialized. 
-        Optional. 
+        created, but it's not initialized.
+        Optional.
         NOTE: make sure to call super().initialize()
         '''
         self._parameters[self.KEY_ENABLED] = True
@@ -121,7 +121,7 @@
     def remove_task(self, tid):
         ''' This function is called from GTG core whenever a task must be
         removed from the backend. Note that the task could be not present here.
-        
+
         @param tid: the id of the task to delete
         '''
         pass
@@ -133,7 +133,7 @@
         This function is needed only in the default backend (XML localfile,
         currently).
         The xml parameter is an object containing GTG default tasks.
-        
+
         @param xml: an xml object containing the default tasks.
         '''
         pass
@@ -141,7 +141,7 @@
     def quit(self, disable = False):
         '''
         Called when GTG quits or the user wants to disable the backend.
-        
+
         @param disable: If disable is True, the backend won't
                         be automatically loaded when GTG starts
         '''
@@ -192,7 +192,7 @@
     # For an example, see the GTG/backends/backend_localfile.py file
     # Each dictionary contains the keys:
     PARAM_DEFAULT_VALUE = "default_value" # its default value
-    PARAM_TYPE = "type"  
+    PARAM_TYPE = "type"
     #PARAM_TYPE is one of the following (changing this changes the way
     # the user can configure the parameter)
     TYPE_PASSWORD = "password" #the real password is stored in the GNOME
@@ -247,7 +247,7 @@
                                          PARAM_TYPE: TYPE_LIST_OF_STRINGS, \
                                          PARAM_DEFAULT_VALUE: [ALLTASKS_TAG], \
                                     }}
-    
+
     #Handy dictionary used in type conversion (from string to type)
     _type_converter = {TYPE_STRING: str,
                        TYPE_INT: int,
@@ -269,7 +269,7 @@
                 temp_dic[key] = value
         for key, value in cls._static_parameters.iteritems():
             temp_dic[key] = value
-        return temp_dic 
+        return temp_dic
 
     def __init__(self, parameters):
         """
@@ -296,7 +296,7 @@
         if Log.is_debugging_mode():
             self.timer_timestep = 5
         else:
-            self.timer_timestep = 1 
+            self.timer_timestep = 1
         self.to_set_timer = None
         self.please_quit = False
         self.cancellation_point = lambda: _cancellation_point(\
@@ -311,8 +311,8 @@
         if hasattr(self._parameters, self.KEY_DEFAULT_BACKEND) and \
                    self._parameters[self.KEY_DEFAULT_BACKEND]:
             #default backends should get all the tasks
-            #NOTE: this shouldn't be needed, but it doesn't cost anything and it
-            #      could avoid potential tasks losses.
+            #NOTE: this shouldn't be needed, but it doesn't cost anything and
+            #      it could avoid potential tasks losses.
             return [self.ALLTASKS_TAG]
         try:
             return self._parameters[self.KEY_ATTACHED_TAGS]
@@ -505,9 +505,9 @@
 
     def get_parameter_type(self, param_name):
         '''
-        Given the name of a parameter, returns its type. If the parameter is one
-        of the default ones, it does not have a type: in that case, it returns
-        None
+        Given the name of a parameter, returns its type. If the parameter is
+         one of the default ones, it does not have a type: in that case, it
+        returns None
 
         @param param_name: the name of the parameter
         @returns string: the type, or None
@@ -519,8 +519,8 @@
 
     def register_datastore(self, datastore):
         '''
-        Setter function to inform the backend about the datastore that's loading
-        it.
+        Setter function to inform the backend about the datastore that's
+        loading it.
 
         @param datastore: a Datastore
         '''
@@ -529,7 +529,6 @@
 ###############################################################################
 ### HELPER FUNCTIONS ##########################################################
 ###############################################################################
-
     def _store_pickled_file(self, path, data):
         '''
         A helper function to save some object in a file.
@@ -543,7 +542,7 @@
         try:
             os.makedirs(os.path.dirname(path))
         except OSError, exception:
-            if exception.errno != errno.EEXIST: 
+            if exception.errno != errno.EEXIST:
                 raise
 
         # Shift backups
@@ -606,7 +605,6 @@
             "loading default data" % self.get_name())
         return default_value
 
-
     def _gtg_task_is_syncable_per_attached_tags(self, task):
         '''
         Helper function which checks if the given task satisfies the filtering
@@ -627,7 +625,6 @@
 ###############################################################################
 ### THREADING #################################################################
 ###############################################################################
-
     def __try_launch_setting_thread(self):
         '''
         Helper function to launch the setting thread, if it's not running.
@@ -640,7 +637,7 @@
     def launch_setting_thread(self, bypass_quit_request = False):
         '''
         This function is launched as a separate thread. Its job is to perform
-        the changes that have been issued from GTG core. 
+        the changes that have been issued from GTG core.
         In particular, for each task in the self.to_set queue, a task
         has to be modified or to be created (if the tid is new), and for
         each task in the self.to_remove queue, a task has to be deleted
@@ -656,7 +653,7 @@
             except IndexError:
                 break
             tid = task.get_id()
-            if tid  not in self.to_remove:
+            if tid not in self.to_remove:
                 self.set_task(task)
 
         while not self.please_quit or bypass_quit_request:
@@ -672,7 +669,7 @@
         ''' Save the task in the backend. In particular, it just enqueues the
         task in the self.to_set queue. A thread will shortly run to apply the
         requested changes.
-        
+
         @param task: the task that should be saved
         '''
         tid = task.get_id()
@@ -683,8 +680,8 @@
     def queue_remove_task(self, tid):
         '''
         Queues task to be removed. In particular, it just enqueues the
-        task in the self.to_remove queue. A thread will shortly run to apply the
-        requested changes.
+        task in the self.to_remove queue. A thread will shortly run to apply
+        the requested changes.
 
         @param tid: The Task ID of the task to be removed
         '''

=== modified file 'GTG/backends/generictomboy.py'
--- GTG/backends/generictomboy.py	2012-11-25 19:19:44 +0000
+++ GTG/backends/generictomboy.py	2012-12-21 16:50:32 +0000
@@ -41,15 +41,13 @@
 from GTG.tools.tags              import extract_tags_from_text
 
 
-
 class GenericTomboy(GenericBackend):
     '''Backend class for Tomboy/Gnote'''
-    
+
 
 ###############################################################################
 ### Backend standard methods ##################################################
 ###############################################################################
-
     def __init__(self, parameters):
         """
         See GenericBackend for an explanation of this function.
@@ -74,7 +72,7 @@
         #NOTE: I'm not sure if this is the case anymore (but it shouldn't hurt
         #      anyway). (invernizzi)
         self._tomboy_setting_timers = {}
-        
+
     def initialize(self):
         '''
         See GenericBackend for an explanation of this function.
@@ -85,10 +83,10 @@
             bus = dbus.SessionBus()
             bus.add_signal_receiver(self.on_note_saved,
                                     dbus_interface = self.BUS_ADDRESS[2],
-                                    signal_name    = "NoteSaved")
+                                    signal_name = "NoteSaved")
             bus.add_signal_receiver(self.on_note_deleted,
                                     dbus_interface = self.BUS_ADDRESS[2],
-                                    signal_name    = "NoteDeleted")
+                                    signal_name = "NoteDeleted")
 
     @interruptible
     def start_get_tasks(self):
@@ -119,6 +117,7 @@
         '''
         See GenericBackend for an explanation of this function.
         '''
+
         def quit_thread():
             while True:
                 try:
@@ -134,7 +133,6 @@
 ###############################################################################
 ### Something got removed #####################################################
 ###############################################################################
-
     @interruptible
     def on_note_deleted(self, note, something):
         '''
@@ -195,12 +193,11 @@
 ###############################################################################
 ### Process tasks #############################################################
 ###############################################################################
-
     def _process_tomboy_note(self, note):
         '''
-        Given a tomboy note, finds out if it must be synced to a GTG note and, 
-        if so, it carries out the synchronization (by creating or updating a GTG
-        task, or deleting itself if the related task has been deleted)
+        Given a tomboy note, finds out if it must be synced to a GTG note and,
+        if so, it carries out the synchronization (by creating or updating a
+        GTG task, or deleting itself if the related task has been deleted)
 
         @param note: a Tomboy note id
         '''
@@ -314,9 +311,8 @@
 ###############################################################################
 ### Helper methods ############################################################
 ###############################################################################
-
     @interruptible
-    def on_note_saved(self,  note):
+    def on_note_saved(self, note):
         '''
         Callback, executed when a tomboy note is saved by Tomboy itself.
         Updates the related GTG task (or creates one, if necessary).
@@ -397,8 +393,8 @@
         Tomboy does not have a "getTitle" and "getText" functions to get the
         title and the text of a note separately. Instead, it has a getContent
         function, that returns both of them.
-        This function splits up the output of getContent into a title string and
-        a text string.
+        This function splits up the output of getContent into a title string
+        and a text string.
 
         @param content: a string, the result of a getContent call
         @returns list: a list composed by [title, text]
@@ -409,7 +405,7 @@
             return content, unicode("")
         title = content[: end_of_title]
         if len(content) > end_of_title:
-            return title, content[end_of_title +1 :]
+            return title, content[end_of_title +1:]
         else:
             return title, unicode("")
 
@@ -488,9 +484,6 @@
 ###############################################################################
 ### Connection handling #######################################################
 ###############################################################################
-
-
-
     class TomboyConnection(Borg):
         '''
         TomboyConnection creates a connection to TOMBOY via DBus and
@@ -501,7 +494,6 @@
                 #do something
         '''
 
-
         def __init__(self, backend, bus_name, bus_path, bus_interface):
             '''
             Sees if a TomboyConnection object already exists. If so, since we
@@ -513,7 +505,7 @@
             @param backend: a reference to a Backend
             @param bus_name: the DBus address of Tomboy
             @param bus_path: the DBus path of Tomboy RemoteControl
-            @param bus_interface: the DBus address of Tomboy RemoteControl 
+            @param bus_interface: the DBus address of Tomboy RemoteControl
             '''
             super(GenericTomboy.TomboyConnection, self).__init__()
             if hasattr(self, "tomboy_connection_is_ok") and \
@@ -537,7 +529,6 @@
             @returns: dbus.Interface
             '''
             return self.tomboy
-                
 
         def __exit__(self, exception_type, value, traceback):
             '''
@@ -556,7 +547,7 @@
                 return True
             else:
                 return False
-        
+
         def tomboy_failed(self):
             """ Handle failed tomboy connection.
 
@@ -566,17 +557,15 @@
                 BackendSignals.ERRNO_DBUS)
             self.backend.quit(disable = True)
 
-
     class DbusWatchdog(Watchdog):
         '''
         A simple watchdog to detect stale dbus connections
         '''
 
-
         def __init__(self, backend):
             '''
-            Simple constructor, which sets _when_taking_too_long as the function
-            to run when the connection is taking too long.
+            Simple constructor, which sets _when_taking_too_long as the
+            function to run when the connection is taking too long.
 
             @param backend: a Backend object
             '''

=== modified file 'GTG/backends/periodicimportbackend.py'
--- GTG/backends/periodicimportbackend.py	2012-11-25 19:19:44 +0000
+++ GTG/backends/periodicimportbackend.py	2012-12-21 16:50:32 +0000
@@ -29,7 +29,6 @@
 from GTG.tools.interruptible     import interruptible
 
 
-
 class PeriodicImportBackend(GenericBackend):
     '''
     This class can be used in place of GenericBackend when a periodic import is
@@ -37,7 +36,7 @@
     changes.
     To use this, only two things are necessary:
         - using do_periodic_import instead of start_get_tasks
-        - having in _static_parameters a "period" key, as in:: 
+        - having in _static_parameters a "period" key, as in::
             "period": { \
                 GenericBackend.PARAM_TYPE: GenericBackend.TYPE_INT, \
                 GenericBackend.PARAM_DEFAULT_VALUE: 2, },
@@ -57,8 +56,8 @@
         next ones.
         '''
         self.cancellation_point()
-        #if we're already importing, we queue a "urgent" import cycle after this
-        #one. The feeling of responsiveness of the backend is improved.
+        #if we're already importing, we queue a "urgent" import cycle after
+        #this one. The feeling of responsiveness of the backend is improved.
         if not self.running_iteration:
             try:
                 #if an iteration was scheduled, we cancel it
@@ -68,7 +67,7 @@
                 pass
             if self.is_enabled() == False:
                 return
-            
+
             #we schedule the next iteration, just in case this one fails
             if not self.urgent_iteration:
                 self.import_timer = threading.Timer( \
@@ -81,7 +80,7 @@
             self._start_get_tasks()
             self.running_iteration = False
             self.cancellation_point()
-            
+
             #execute eventual urgent iteration
             #NOTE: this way, if the iteration fails, the whole periodic import
             #      cycle fails.
@@ -91,7 +90,6 @@
         else:
             self.urgent_iteration = True
 
-
     def _start_get_tasks(self):
         '''
         This function executes an imports and schedules the next
@@ -114,4 +112,3 @@
             self.import_timer.join()
         except Exception:
             pass
-

=== modified file 'GTG/backends/syncengine.py'
--- GTG/backends/syncengine.py	2012-11-25 19:19:44 +0000
+++ GTG/backends/syncengine.py	2012-12-21 16:50:32 +0000
@@ -23,7 +23,7 @@
  - We have two sets of generic objects (local and remote)
  - We present one object of either one of the sets and ask the library what's
  the state of its synchronization
- - the library will tell us if we need to add a clone object in the other set, 
+ - the library will tell us if we need to add a clone object in the other set,
    update it or, if the other one has been removed, remove also this one
 '''
 from GTG.tools.twokeydict import TwoKeyDict
@@ -33,7 +33,6 @@
 TYPE_REMOTE = "remote"
 
 
-
 class SyncMeme(object):
     '''
     A SyncMeme is the object storing the data needed to keep track of the state
@@ -45,7 +44,6 @@
     #NOTE: Checking objects CRCs would make this check nicer, as we could know
     #      if the object was really changed, or it has just updated its
     #      modified time (invernizzi)
-
     def __init__(self,
                  local_modified = None,
                  remote_modified = None,
@@ -57,8 +55,9 @@
 
         @param local_modified: the modified time for the local object
         @param remote_modified: the modified time for the remote object
-        @param origin: an object that identifies whether the local or the remote is
-                       the original object, the other one being a copy.
+        @param origin: an object that identifies whether the local or the
+                       remote is the original object, the other one being a
+                       copy.
         '''
         if local_modified != None:
             self.set_local_last_modified(local_modified)
@@ -98,9 +97,9 @@
     def which_is_newest(self, local_modified, remote_modified):
         '''
         Given the updated modified time for both the local and the remote
-        objects, it checks them against the stored modified times and 
+        objects, it checks them against the stored modified times and
         then against each other.
-        
+
         @returns string: "local"- if the local object has been modified and its
                          the newest
                          "remote" - the same for the remote object
@@ -114,7 +113,7 @@
             return "local"
         else:
             return "remote"
-    
+
     def get_origin(self):
         '''
         Returns the name of the source that firstly presented the object
@@ -125,21 +124,20 @@
         '''
         Sets the source that presented the object for the first time. This
         source holds the original object, while the other holds the copy.
-        This can be useful in the case of "lost syncability" (see the SyncEngine
-        for an explaination).
-            
+        This can be useful in the case of "lost syncability" (see the
+        SyncEngine for an explaination).
+
         @param origin: object representing the source
         '''
         self.origin = origin
 
 
-
 class SyncMemes(TwoKeyDict):
     '''
     A TwoKeyDict, with just the names changed to be better understandable.
-    The meaning of these names is explained in the SyncEngine class description.
-    It's used to store a set of SyncMeme objects, each one keeping storing all
-    the data needed to keep track of a single relationship.
+    The meaning of these names is explained in the SyncEngine class
+    description. It's used to store a set of SyncMeme objects, each one keeping
+    storing all the data needed to keep track of a single relationship.
     '''
 
 
@@ -153,7 +151,6 @@
     get_all_remote = TwoKeyDict._get_all_secondary_keys
 
 
-
 class SyncEngine(object):
     '''
     The SyncEngine is an object useful in keeping two sets of objects
@@ -161,8 +158,8 @@
     One set is called the Local set, the other is the Remote one.
     It stores the state of the synchronization and the latest state of each
     object.
-    When asked, it can tell if a couple of related objects are up to date in the
-    sync and, if not, which one must be updated.
+    When asked, it can tell if a couple of related objects are up to date in
+    the sync and, if not, which one must be updated.
 
     It stores the state of each relationship in a series of SyncMeme.
     '''
@@ -170,7 +167,7 @@
 
     UPDATE = "update"
     REMOVE = "remove"
-    ADD    = "add"
+    ADD = "add"
     LOST_SYNCABILITY = "lost syncability"
 
     def __init__(self):
@@ -195,10 +192,10 @@
         A particular case happens if the other object is present, but the
         "is_syncable" parameter (which tells that we intend to keep these two
         objects in sync) is set to False. In this case, this function returns
-        that the Syncability property has been lost. This case is interesting if
-        we want to delete one of the two objects (the one that has been cloned
-        from the original).
-        
+        that the Syncability property has been lost. This case is interesting
+        if we want to delete one of the two objects (the one that has been
+        cloned from the original).
+
         @param element_id: the id of the element we're analysing.
         @param is_local: True if the element analysed is the local one (not the
                          remote)
@@ -242,7 +239,7 @@
         Shortcut to call _analyze_element for a remote element
         '''
         return self._analyze_element(element_id, False, *other_args)
-    
+
     def record_relationship(self, local_id, remote_id, meme):
         '''
         Records that an object from the local set is related with one a remote
@@ -285,4 +282,3 @@
             return getattr(self.sync_memes, attr)
         else:
             raise AttributeError
-

=== modified file 'GTG/backends/twitter.py'
--- GTG/backends/twitter.py	2012-05-01 15:53:24 +0000
+++ GTG/backends/twitter.py	2012-12-21 16:50:32 +0000
@@ -42,9 +42,9 @@
     import json
 
 try:
-  from hashlib import md5
+    from hashlib import md5
 except ImportError:
-  from md5 import md5
+    from md5 import md5
 
 
 CHARACTER_LIMIT = 140
@@ -54,2310 +54,2391 @@
 
 
 class TwitterError(Exception):
-  '''Base class for Twitter errors'''
-  
-  @property
-  def message(self):
-    '''Returns the first argument used to construct this error.'''
-    return self.args[0]
+    '''Base class for Twitter errors'''
+
+    @property
+    def message(self):
+        '''Returns the first argument used to construct this error.'''
+        return self.args[0]
 
 
 class Status(object):
-  '''A class representing the Status structure used by the twitter API.
-
-  The Status structure exposes the following properties:
-
-      - status.created_at
-      - status.created_at_in_seconds # read only
-      - status.favorited
-      - status.in_reply_to_screen_name
-      - status.in_reply_to_user_id
-      - status.in_reply_to_status_id
-      - status.truncated
-      - status.source
-      - status.id
-      - status.text
-      - status.location
-      - status.relative_created_at # read only
-      - status.user
-  '''
-  def __init__(self,
-               created_at=None,
-               favorited=None,
-               id=None,
-               text=None,
-               location=None,
-               user=None,
-               in_reply_to_screen_name=None,
-               in_reply_to_user_id=None,
-               in_reply_to_status_id=None,
-               truncated=None,
-               source=None,
-               now=None):
-    '''An object to hold a Twitter status message.
-
-    This class is normally instantiated by the twitter.Api class and
-    returned in a sequence.
-
-    Note: Dates are posted in the form "Sat Jan 27 04:17:38 +0000 2007"
-
-    @param created_at: The time this status message was posted
-    @param favorited: Whether this is a favorite of the authenticated user
-    @param id: The unique id of this status message
-    @param text: The text of this status message
-    @param location: the geolocation string associated with this message
-    @param relative_created_at:
-        A human readable string representing the posting time
-    @param user:
-        A twitter.User instance representing the person posting the message
-    @param now:
-        The current time, if the client choses to set it.  Defaults to the
-        wall clock time.
-    '''
-    self.created_at = created_at
-    self.favorited = favorited
-    self.id = id
-    self.text = text
-    self.location = location
-    self.user = user
-    self.now = now
-    self.in_reply_to_screen_name = in_reply_to_screen_name
-    self.in_reply_to_user_id = in_reply_to_user_id
-    self.in_reply_to_status_id = in_reply_to_status_id
-    self.truncated = truncated
-    self.source = source
-
-  def GetCreatedAt(self):
-    '''Get the time this status message was posted.
-
-    @returns: The time this status message was posted
-    '''
-    return self._created_at
-
-  def SetCreatedAt(self, created_at):
-    '''Set the time this status message was posted.
-
-    @param created_at: The time this status message was created
-    '''
-    self._created_at = created_at
-
-  created_at = property(GetCreatedAt, SetCreatedAt,
-                        doc='The time this status message was posted.')
-
-  def GetCreatedAtInSeconds(self):
-    '''Get the time this status message was posted, in seconds since the epoch.
-
-    @returns: The time this status message was posted, in seconds since the epoch.
-    '''
-    return calendar.timegm(rfc822.parsedate(self.created_at))
-
-  created_at_in_seconds = property(GetCreatedAtInSeconds,
-                                   doc="The time this status message was "
-                                       "posted, in seconds since the epoch")
-
-  def GetFavorited(self):
-    '''Get the favorited setting of this status message.
-
-    @returns: True if this status message is favorited; False otherwise
-    '''
-    return self._favorited
-
-  def SetFavorited(self, favorited):
-    '''Set the favorited state of this status message.
-
-    @param favorited: boolean True/False favorited state of this status message
-    '''
-    self._favorited = favorited
-
-  favorited = property(GetFavorited, SetFavorited,
-                       doc='The favorited state of this status message.')
-
-  def GetId(self):
-    '''Get the unique id of this status message.
-
-    @returns: The unique id of this status message
-    '''
-    return self._id
-
-  def SetId(self, id):
-    '''Set the unique id of this status message.
-
-    @param id: The unique id of this status message
-    '''
-    self._id = id
-
-  id = property(GetId, SetId,
-                doc='The unique id of this status message.')
-
-  def GetInReplyToScreenName(self):
-    return self._in_reply_to_screen_name
-
-  def SetInReplyToScreenName(self, in_reply_to_screen_name):
-    self._in_reply_to_screen_name = in_reply_to_screen_name
-
-  in_reply_to_screen_name = property(GetInReplyToScreenName, SetInReplyToScreenName,
-                doc='')
-
-  def GetInReplyToUserId(self):
-    return self._in_reply_to_user_id
-
-  def SetInReplyToUserId(self, in_reply_to_user_id):
-    self._in_reply_to_user_id = in_reply_to_user_id
-
-  in_reply_to_user_id = property(GetInReplyToUserId, SetInReplyToUserId,
-                doc='')
-
-  def GetInReplyToStatusId(self):
-    return self._in_reply_to_status_id
-
-  def SetInReplyToStatusId(self, in_reply_to_status_id):
-    self._in_reply_to_status_id = in_reply_to_status_id
-
-  in_reply_to_status_id = property(GetInReplyToStatusId, SetInReplyToStatusId,
-                doc='')
-
-  def GetTruncated(self):
-    return self._truncated
-
-  def SetTruncated(self, truncated):
-    self._truncated = truncated
-
-  truncated = property(GetTruncated, SetTruncated,
-                doc='')
-
-  def GetSource(self):
-    return self._source
-
-  def SetSource(self, source):
-    self._source = source
-
-  source = property(GetSource, SetSource,
-                doc='')
-
-  def GetText(self):
-    '''Get the text of this status message.
-
-    @returns: The text of this status message.
-    '''
-    return self._text
-
-  def SetText(self, text):
-    '''Set the text of this status message.
-
-    @param text: The text of this status message
-    '''
-    self._text = text
-
-  text = property(GetText, SetText,
-                  doc='The text of this status message')
-
-  def GetLocation(self):
-    '''Get the geolocation associated with this status message
-
-    @returns: The geolocation string of this status message.
-    '''
-    return self._location
-
-  def SetLocation(self, location):
-    '''Set the geolocation associated with this status message
-
-    @param location: The geolocation string of this status message
-    '''
-    self._location = location
-
-  location = property(GetLocation, SetLocation,
-                      doc='The geolocation string of this status message')
-
-  def GetRelativeCreatedAt(self):
-    '''Get a human redable string representing the posting time
-
-    @returns: A human readable string representing the posting time
-    '''
-    fudge = 1.25
-    delta  = long(self.now) - long(self.created_at_in_seconds)
-
-    if delta < (1 * fudge):
-      return 'about a second ago'
-    elif delta < (60 * (1/fudge)):
-      return 'about %d seconds ago' % (delta)
-    elif delta < (60 * fudge):
-      return 'about a minute ago'
-    elif delta < (60 * 60 * (1/fudge)):
-      return 'about %d minutes ago' % (delta / 60)
-    elif delta < (60 * 60 * fudge) or delta / (60 * 60) == 1:
-      return 'about an hour ago'
-    elif delta < (60 * 60 * 24 * (1/fudge)):
-      return 'about %d hours ago' % (delta / (60 * 60))
-    elif delta < (60 * 60 * 24 * fudge) or delta / (60 * 60 * 24) == 1:
-      return 'about a day ago'
-    else:
-      return 'about %d days ago' % (delta / (60 * 60 * 24))
-
-  relative_created_at = property(GetRelativeCreatedAt,
-                                 doc='Get a human readable string representing'
-                                     'the posting time')
-
-  def GetUser(self):
-    '''Get a twitter.User reprenting the entity posting this status message.
-
-    @returns: A twitter.User reprenting the entity posting this status message
-    '''
-    return self._user
-
-  def SetUser(self, user):
-    '''Set a twitter.User reprenting the entity posting this status message.
-
-    @param user: A twitter.User reprenting the entity posting this status message
-    '''
-    self._user = user
-
-  user = property(GetUser, SetUser,
-                  doc='A twitter.User reprenting the entity posting this '
-                      'status message')
-
-  def GetNow(self):
-    '''Get the wallclock time for this status message.
-
-    Used to calculate relative_created_at.  Defaults to the time
-    the object was instantiated.
-
-    @returns: Whatever the status instance believes the current time to be,
-        in seconds since the epoch.
-    '''
-    if self._now is None:
-      self._now = time.time()
-    return self._now
-
-  def SetNow(self, now):
-    '''Set the wallclock time for this status message.
-
-    Used to calculate relative_created_at.  Defaults to the time
-    the object was instantiated.
-
-    @param now: The wallclock time for this instance.
-    '''
-    self._now = now
-
-  now = property(GetNow, SetNow,
-                 doc='The wallclock time for this status instance.')
-
-
-  def __ne__(self, other):
-    return not self.__eq__(other)
-
-  def __eq__(self, other):
-    try:
-      return other and \
-             self.created_at == other.created_at and \
-             self.id == other.id and \
-             self.text == other.text and \
-             self.location == other.location and \
-             self.user == other.user and \
-             self.in_reply_to_screen_name == other.in_reply_to_screen_name and \
-             self.in_reply_to_user_id == other.in_reply_to_user_id and \
-             self.in_reply_to_status_id == other.in_reply_to_status_id and \
-             self.truncated == other.truncated and \
-             self.favorited == other.favorited and \
-             self.source == other.source
-    except AttributeError:
-      return False
-
-  def __str__(self):
-    '''A string representation of this twitter.Status instance.
-
-    The return value is the same as the JSON string representation.
-
-    @returns: A string representation of this twitter.Status instance.
-    '''
-    return self.AsJsonString()
-
-  def AsJsonString(self):
-    '''A JSON string representation of this twitter.Status instance.
-
-    @returns: A JSON string representation of this twitter.Status instance
-   '''
-    return json.dumps(self.AsDict(), sort_keys=True)
-
-  def AsDict(self):
-    '''A dict representation of this twitter.Status instance.
-
-    The return value uses the same key names as the JSON representation.
-
-    @return: A dict representing this twitter.Status instance
-    '''
-    data = {}
-    if self.created_at:
-      data['created_at'] = self.created_at
-    if self.favorited:
-      data['favorited'] = self.favorited
-    if self.id:
-      data['id'] = self.id
-    if self.text:
-      data['text'] = self.text
-    if self.location:
-      data['location'] = self.location  
-    if self.user:
-      data['user'] = self.user.AsDict()
-    if self.in_reply_to_screen_name:
-      data['in_reply_to_screen_name'] = self.in_reply_to_screen_name
-    if self.in_reply_to_user_id:
-      data['in_reply_to_user_id'] = self.in_reply_to_user_id
-    if self.in_reply_to_status_id:
-      data['in_reply_to_status_id'] = self.in_reply_to_status_id
-    if self.truncated is not None:
-      data['truncated'] = self.truncated
-    if self.favorited is not None:
-      data['favorited'] = self.favorited
-    if self.source:
-      data['source'] = self.source
-    return data
-
-  @staticmethod
-  def NewFromJsonDict(data):
-    '''Create a new instance based on a JSON dict.
-
-    @param data: A JSON dict, as converted from the JSON in the twitter API
-    @returns: A twitter.Status instance
-    '''
-    if 'user' in data:
-      user = User.NewFromJsonDict(data['user'])
-    else:
-      user = None
-    return Status(created_at=data.get('created_at', None),
-                  favorited=data.get('favorited', None),
-                  id=data.get('id', None),
-                  text=data.get('text', None),
-                  location=data.get('location', None),
-                  in_reply_to_screen_name=data.get('in_reply_to_screen_name', None),
-                  in_reply_to_user_id=data.get('in_reply_to_user_id', None),
-                  in_reply_to_status_id=data.get('in_reply_to_status_id', None),
-                  truncated=data.get('truncated', None),
-                  source=data.get('source', None),
-                  user=user)
+    '''A class representing the Status structure used by the twitter API.
+
+    The Status structure exposes the following properties:
+
+        - status.created_at
+        - status.created_at_in_seconds # read only
+        - status.favorited
+        - status.in_reply_to_screen_name
+        - status.in_reply_to_user_id
+        - status.in_reply_to_status_id
+        - status.truncated
+        - status.source
+        - status.id
+        - status.text
+        - status.location
+        - status.relative_created_at # read only
+        - status.user
+    '''
+
+    def __init__(self,
+                created_at=None,
+                favorited=None,
+                id=None,
+                text=None,
+                location=None,
+                user=None,
+                in_reply_to_screen_name=None,
+                in_reply_to_user_id=None,
+                in_reply_to_status_id=None,
+                truncated=None,
+                source=None,
+                now=None):
+        '''An object to hold a Twitter status message.
+
+        This class is normally instantiated by the twitter.Api class and
+        returned in a sequence.
+
+        Note: Dates are posted in the form "Sat Jan 27 04:17:38 +0000 2007"
+
+        @param created_at: The time this status message was posted
+        @param favorited: Whether this is a favorite of the authenticated user
+        @param id: The unique id of this status message
+        @param text: The text of this status message
+        @param location: the geolocation string associated with this message
+        @param relative_created_at:
+            A human readable string representing the posting time
+        @param user:
+            A twitter.User instance representing the person posting the message
+        @param now:
+            The current time, if the client choses to set it.  Defaults to the
+            wall clock time.
+        '''
+        self.created_at = created_at
+        self.favorited = favorited
+        self.id = id
+        self.text = text
+        self.location = location
+        self.user = user
+        self.now = now
+        self.in_reply_to_screen_name = in_reply_to_screen_name
+        self.in_reply_to_user_id = in_reply_to_user_id
+        self.in_reply_to_status_id = in_reply_to_status_id
+        self.truncated = truncated
+        self.source = source
+
+    def GetCreatedAt(self):
+        '''Get the time this status message was posted.
+
+        @returns: The time this status message was posted
+        '''
+        return self._created_at
+
+    def SetCreatedAt(self, created_at):
+        '''Set the time this status message was posted.
+
+        @param created_at: The time this status message was created
+        '''
+        self._created_at = created_at
+
+        created_at = property(GetCreatedAt, SetCreatedAt,
+                            doc='The time this status message was posted.')
+
+    def GetCreatedAtInSeconds(self):
+        '''Get the time this status message was posted, in seconds since the
+        epoch.
+
+        @returns: The time this status message was posted, in seconds since the
+                  epoch.
+        '''
+        return calendar.timegm(rfc822.parsedate(self.created_at))
+
+        created_at_in_seconds = property(GetCreatedAtInSeconds,
+                                       doc="The time this status message was "
+                                         "posted, in seconds since the epoch")
+
+    def GetFavorited(self):
+        '''Get the favorited setting of this status message.
+
+        @returns: True if this status message is favorited; False otherwise
+        '''
+        return self._favorited
+
+    def SetFavorited(self, favorited):
+        '''Set the favorited state of this status message.
+
+        @param favorited: boolean True/False favorited state of this status
+                           message
+        '''
+        self._favorited = favorited
+
+        favorited = property(GetFavorited, SetFavorited,
+                           doc='The favorited state of this status message.')
+
+    def GetId(self):
+        '''Get the unique id of this status message.
+
+        @returns: The unique id of this status message
+        '''
+        return self._id
+
+    def SetId(self, id):
+        '''Set the unique id of this status message.
+
+        @param id: The unique id of this status message
+        '''
+        self._id = id
+
+        id = property(GetId, SetId,
+                    doc='The unique id of this status message.')
+
+    def GetInReplyToScreenName(self):
+        return self._in_reply_to_screen_name
+
+    def SetInReplyToScreenName(self, in_reply_to_screen_name):
+        self._in_reply_to_screen_name = in_reply_to_screen_name
+
+        in_reply_to_screen_name = property(GetInReplyToScreenName,
+                                   SetInReplyToScreenName, doc='')
+
+    def GetInReplyToUserId(self):
+        return self._in_reply_to_user_id
+
+    def SetInReplyToUserId(self, in_reply_to_user_id):
+        self._in_reply_to_user_id = in_reply_to_user_id
+
+        in_reply_to_user_id = property(GetInReplyToUserId, SetInReplyToUserId,
+                doc='')
+
+    def GetInReplyToStatusId(self):
+        return self._in_reply_to_status_id
+
+    def SetInReplyToStatusId(self, in_reply_to_status_id):
+        self._in_reply_to_status_id = in_reply_to_status_id
+
+        in_reply_to_status_id = property(GetInReplyToStatusId,
+                                               SetInReplyToStatusId, doc='')
+
+    def GetTruncated(self):
+        return self._truncated
+
+    def SetTruncated(self, truncated):
+        self._truncated = truncated
+
+        truncated = property(GetTruncated, SetTruncated,
+                    doc='')
+
+    def GetSource(self):
+        return self._source
+
+    def SetSource(self, source):
+        self._source = source
+
+        source = property(GetSource, SetSource,
+                    doc='')
+
+    def GetText(self):
+        '''Get the text of this status message.
+
+        @returns: The text of this status message.
+        '''
+        return self._text
+
+    def SetText(self, text):
+        '''Set the text of this status message.
+
+        @param text: The text of this status message
+        '''
+        self._text = text
+
+        text = property(GetText, SetText,
+                      doc='The text of this status message')
+
+    def GetLocation(self):
+        '''Get the geolocation associated with this status message
+
+        @returns: The geolocation string of this status message.
+        '''
+        return self._location
+
+    def SetLocation(self, location):
+        '''Set the geolocation associated with this status message
+
+        @param location: The geolocation string of this status message
+        '''
+        self._location = location
+
+        location = property(GetLocation, SetLocation,
+                          doc='The geolocation string of this status message')
+
+    def GetRelativeCreatedAt(self):
+        '''Get a human redable string representing the posting time
+
+        @returns: A human readable string representing the posting time
+        '''
+        fudge = 1.25
+        delta = long(self.now) - long(self.created_at_in_seconds)
+
+        if delta < (1 * fudge):
+            return 'about a second ago'
+        elif delta < (60 * (1/fudge)):
+            return 'about %d seconds ago' % (delta)
+        elif delta < (60 * fudge):
+            return 'about a minute ago'
+        elif delta < (60 * 60 * (1/fudge)):
+            return 'about %d minutes ago' % (delta / 60)
+        elif delta < (60 * 60 * fudge) or delta / (60 * 60) == 1:
+            return 'about an hour ago'
+        elif delta < (60 * 60 * 24 * (1/fudge)):
+            return 'about %d hours ago' % (delta / (60 * 60))
+        elif delta < (60 * 60 * 24 * fudge) or delta / (60 * 60 * 24) == 1:
+            return 'about a day ago'
+        else:
+            return 'about %d days ago' % (delta / (60 * 60 * 24))
+
+        relative_created_at = property(GetRelativeCreatedAt,
+                                     doc='Get a human readable string'
+                                         ' representing the posting time')
+
+    def GetUser(self):
+        '''Get a twitter.User reprenting the entity posting this status message
+
+        @returns: A twitter.User reprenting the entity posting this status
+                  message
+        '''
+        return self._user
+
+    def SetUser(self, user):
+        '''Set a twitter.User reprenting the entity posting this status message
+
+        @param user: A twitter.User reprenting the entity posting this status
+                     message
+        '''
+        self._user = user
+
+        user = property(GetUser, SetUser,
+                      doc='A twitter.User reprenting the entity posting this '
+                          'status message')
+
+    def GetNow(self):
+        '''Get the wallclock time for this status message.
+
+        Used to calculate relative_created_at.  Defaults to the time
+        the object was instantiated.
+
+        @returns: Whatever the status instance believes the current time to be,
+            in seconds since the epoch.
+        '''
+        if self._now is None:
+            self._now = time.time()
+        return self._now
+
+    def SetNow(self, now):
+        '''Set the wallclock time for this status message.
+
+        Used to calculate relative_created_at.  Defaults to the time
+        the object was instantiated.
+
+        @param now: The wallclock time for this instance.
+        '''
+        self._now = now
+
+        now = property(GetNow, SetNow,
+                     doc='The wallclock time for this status instance.')
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
+    def __eq__(self, other):
+        try:
+            return other and \
+                 self.created_at == other.created_at and \
+                 self.id == other.id and \
+                 self.text == other.text and \
+                 self.location == other.location and \
+                 self.user == other.user and \
+           self.in_reply_to_screen_name == other.in_reply_to_screen_name and \
+                 self.in_reply_to_user_id == other.in_reply_to_user_id and \
+                 self.in_reply_to_status_id == other.in_reply_to_status_id and\
+                 self.truncated == other.truncated and \
+                 self.favorited == other.favorited and \
+                 self.source == other.source
+        except AttributeError:
+            return False
+
+    def __str__(self):
+        '''A string representation of this twitter.Status instance.
+
+        The return value is the same as the JSON string representation.
+
+        @returns: A string representation of this twitter.Status instance.
+        '''
+        return self.AsJsonString()
+
+    def AsJsonString(self):
+        '''A JSON string representation of this twitter.Status instance.
+
+        @returns: A JSON string representation of this twitter.Status instance
+        '''
+        return json.dumps(self.AsDict(), sort_keys=True)
+
+    def AsDict(self):
+        '''A dict representation of this twitter.Status instance.
+
+        The return value uses the same key names as the JSON representation.
+
+        @return: A dict representing this twitter.Status instance
+        '''
+        data = {}
+        if self.created_at:
+            data['created_at'] = self.created_at
+        if self.favorited:
+            data['favorited'] = self.favorited
+        if self.id:
+            data['id'] = self.id
+        if self.text:
+            data['text'] = self.text
+        if self.location:
+            data['location'] = self.location
+        if self.user:
+            data['user'] = self.user.AsDict()
+        if self.in_reply_to_screen_name:
+            data['in_reply_to_screen_name'] = self.in_reply_to_screen_name
+        if self.in_reply_to_user_id:
+            data['in_reply_to_user_id'] = self.in_reply_to_user_id
+        if self.in_reply_to_status_id:
+            data['in_reply_to_status_id'] = self.in_reply_to_status_id
+        if self.truncated is not None:
+            data['truncated'] = self.truncated
+        if self.favorited is not None:
+            data['favorited'] = self.favorited
+        if self.source:
+            data['source'] = self.source
+        return data
+
+    @staticmethod
+    def NewFromJsonDict(data):
+        '''Create a new instance based on a JSON dict.
+
+        @param data: A JSON dict, as converted from the JSON in the twitter API
+
+        @returns: A twitter.Status instance
+        '''
+        if 'user' in data:
+            user = User.NewFromJsonDict(data['user'])
+        else:
+            user = None
+        return Status(created_at=data.get('created_at', None),
+                      favorited=data.get('favorited', None),
+                      id=data.get('id', None),
+                      text=data.get('text', None),
+                      location=data.get('location', None),
+             in_reply_to_screen_name=data.get('in_reply_to_screen_name', None),
+                     in_reply_to_user_id=data.get('in_reply_to_user_id', None),
+                 in_reply_to_status_id=data.get('in_reply_to_status_id', None),
+                      truncated=data.get('truncated', None),
+                      source=data.get('source', None),
+                      user=user)
 
 
 class User(object):
-  '''A class representing the User structure used by the twitter API.
-
-  The User structure exposes the following properties:
-
-    - user.id
-    - user.name
-    - user.screen_name
-    - user.location
-    - user.description
-    - user.profile_image_url
-    - user.profile_background_tile
-    - user.profile_background_image_url
-    - user.profile_sidebar_fill_color
-    - user.profile_background_color
-    - user.profile_link_color
-    - user.profile_text_color
-    - user.protected
-    - user.utc_offset
-    - user.time_zone
-    - user.url
-    - user.status
-    - user.statuses_count
-    - user.followers_count
-    - user.friends_count
-    - user.favourites_count
-  '''
-  def __init__(self,
-               id=None,
-               name=None,
-               screen_name=None,
-               location=None,
-               description=None,
-               profile_image_url=None,
-               profile_background_tile=None,
-               profile_background_image_url=None,
-               profile_sidebar_fill_color=None,
-               profile_background_color=None,
-               profile_link_color=None,
-               profile_text_color=None,
-               protected=None,
-               utc_offset=None,
-               time_zone=None,
-               followers_count=None,
-               friends_count=None,
-               statuses_count=None,
-               favourites_count=None,
-               url=None,
-               status=None):
-    self.id = id
-    self.name = name
-    self.screen_name = screen_name
-    self.location = location
-    self.description = description
-    self.profile_image_url = profile_image_url
-    self.profile_background_tile = profile_background_tile
-    self.profile_background_image_url = profile_background_image_url
-    self.profile_sidebar_fill_color = profile_sidebar_fill_color
-    self.profile_background_color = profile_background_color
-    self.profile_link_color = profile_link_color
-    self.profile_text_color = profile_text_color
-    self.protected = protected
-    self.utc_offset = utc_offset
-    self.time_zone = time_zone
-    self.followers_count = followers_count
-    self.friends_count = friends_count
-    self.statuses_count = statuses_count
-    self.favourites_count = favourites_count
-    self.url = url
-    self.status = status
-
-
-  def GetId(self):
-    '''Get the unique id of this user.
-
-    @returns: The unique id of this user
-    '''
-    return self._id
-
-  def SetId(self, id):
-    '''Set the unique id of this user.
-
-    @param: id: The unique id of this user.
-    '''
-    self._id = id
-
-  id = property(GetId, SetId,
-                doc='The unique id of this user.')
-
-  def GetName(self):
-    '''Get the real name of this user.
-
-    @returns: The real name of this user
-    '''
-    return self._name
-
-  def SetName(self, name):
-    '''Set the real name of this user.
-
-    @param name: The real name of this user
-    '''
-    self._name = name
-
-  name = property(GetName, SetName,
-                  doc='The real name of this user.')
-
-  def GetScreenName(self):
-    '''Get the short username of this user.
-
-    @returns: The short username of this user
-    '''
-    return self._screen_name
-
-  def SetScreenName(self, screen_name):
-    '''Set the short username of this user.
-
-    @param screen_name: the short username of this user
-    '''
-    self._screen_name = screen_name
-
-  screen_name = property(GetScreenName, SetScreenName,
-                         doc='The short username of this user.')
-
-  def GetLocation(self):
-    '''Get the geographic location of this user.
-
-    @returns: The geographic location of this user
-    '''
-    return self._location
-
-  def SetLocation(self, location):
-    '''Set the geographic location of this user.
-
-    @param location: The geographic location of this user
-    '''
-    self._location = location
-
-  location = property(GetLocation, SetLocation,
-                      doc='The geographic location of this user.')
-
-  def GetDescription(self):
-    '''Get the short text description of this user.
-
-    @returns: The short text description of this user
-    '''
-    return self._description
-
-  def SetDescription(self, description):
-    '''Set the short text description of this user.
-
-    @param description: The short text description of this user
-    '''
-    self._description = description
-
-  description = property(GetDescription, SetDescription,
-                         doc='The short text description of this user.')
-
-  def GetUrl(self):
-    '''Get the homepage url of this user.
-
-    @returns: The homepage url of this user
-    '''
-    return self._url
-
-  def SetUrl(self, url):
-    '''Set the homepage url of this user.
-
-    @param url: The homepage url of this user
-    '''
-    self._url = url
-
-  url = property(GetUrl, SetUrl,
-                 doc='The homepage url of this user.')
-
-  def GetProfileImageUrl(self):
-    '''Get the url of the thumbnail of this user.
-
-    @returns: The url of the thumbnail of this user
-    '''
-    return self._profile_image_url
-
-  def SetProfileImageUrl(self, profile_image_url):
-    '''Set the url of the thumbnail of this user.
-
-    @param profile_image_url: The url of the thumbnail of this user
-    '''
-    self._profile_image_url = profile_image_url
-
-  profile_image_url= property(GetProfileImageUrl, SetProfileImageUrl,
-                              doc='The url of the thumbnail of this user.')
-
-  def GetProfileBackgroundTile(self):
-    '''Boolean for whether to tile the profile background image.
-
-    @returns: True if the background is to be tiled, False if not, None if unset.
-    '''
-    return self._profile_background_tile
-
-  def SetProfileBackgroundTile(self, profile_background_tile):
-    '''Set the boolean flag for whether to tile the profile background image.
-
-    @param profile_background_tile: Boolean flag for whether to tile or not.
-    '''
-    self._profile_background_tile = profile_background_tile
-
-  profile_background_tile = property(GetProfileBackgroundTile, SetProfileBackgroundTile,
-                                     doc='Boolean for whether to tile the background image.')
-
-  def GetProfileBackgroundImageUrl(self):
-    return self._profile_background_image_url
-
-  def SetProfileBackgroundImageUrl(self, profile_background_image_url):
-    self._profile_background_image_url = profile_background_image_url
-
-  profile_background_image_url = property(GetProfileBackgroundImageUrl, SetProfileBackgroundImageUrl,
-                                          doc='The url of the profile background of this user.')
-
-  def GetProfileSidebarFillColor(self):
-    return self._profile_sidebar_fill_color
-
-  def SetProfileSidebarFillColor(self, profile_sidebar_fill_color):
-    self._profile_sidebar_fill_color = profile_sidebar_fill_color
-
-  profile_sidebar_fill_color = property(GetProfileSidebarFillColor, SetProfileSidebarFillColor)
-
-  def GetProfileBackgroundColor(self):
-    return self._profile_background_color
-
-  def SetProfileBackgroundColor(self, profile_background_color):
-    self._profile_background_color = profile_background_color
-
-  profile_background_color = property(GetProfileBackgroundColor, SetProfileBackgroundColor)
-
-  def GetProfileLinkColor(self):
-    return self._profile_link_color
-
-  def SetProfileLinkColor(self, profile_link_color):
-    self._profile_link_color = profile_link_color
-
-  profile_link_color = property(GetProfileLinkColor, SetProfileLinkColor)
-
-  def GetProfileTextColor(self):
-    return self._profile_text_color
-
-  def SetProfileTextColor(self, profile_text_color):
-    self._profile_text_color = profile_text_color
-
-  profile_text_color = property(GetProfileTextColor, SetProfileTextColor)
-
-  def GetProtected(self):
-    return self._protected
-
-  def SetProtected(self, protected):
-    self._protected = protected
-
-  protected = property(GetProtected, SetProtected)
-
-  def GetUtcOffset(self):
-    return self._utc_offset
-
-  def SetUtcOffset(self, utc_offset):
-    self._utc_offset = utc_offset
-
-  utc_offset = property(GetUtcOffset, SetUtcOffset)
-
-  def GetTimeZone(self):
-    '''Returns the current time zone string for the user.
-
-    @returns: The descriptive time zone string for the user.
-    '''
-    return self._time_zone
-
-  def SetTimeZone(self, time_zone):
-    '''Sets the user's time zone string.
-
-    @param time_zone: The descriptive time zone to assign for the user.
-    '''
-    self._time_zone = time_zone
-
-  time_zone = property(GetTimeZone, SetTimeZone)
-
-  def GetStatus(self):
-    '''Get the latest twitter.Status of this user.
-
-    @returns: The latest twitter.Status of this user
-    '''
-    return self._status
-
-  def SetStatus(self, status):
-    '''Set the latest twitter.Status of this user.
-
-    @param status: The latest twitter.Status of this user
-    '''
-    self._status = status
-
-  status = property(GetStatus, SetStatus,
-                  doc='The latest twitter.Status of this user.')
-
-  def GetFriendsCount(self):
-    '''Get the friend count for this user.
-    
-    @returns: The number of users this user has befriended.
-    '''
-    return self._friends_count
-
-  def SetFriendsCount(self, count):
-    '''Set the friend count for this user.
-
-    @param count: The number of users this user has befriended.
-    '''
-    self._friends_count = count
-
-  friends_count = property(GetFriendsCount, SetFriendsCount,
-                  doc='The number of friends for this user.')
-
-  def GetFollowersCount(self):
-    '''Get the follower count for this user.
-    
-    @returns: The number of users following this user.
-    '''
-    return self._followers_count
-
-  def SetFollowersCount(self, count):
-    '''Set the follower count for this user.
-
-    @param count: The number of users following this user.
-    '''
-    self._followers_count = count
-
-  followers_count = property(GetFollowersCount, SetFollowersCount,
-                  doc='The number of users following this user.')
-
-  def GetStatusesCount(self):
-    '''Get the number of status updates for this user.
-    
-    @returns: The number of status updates for this user.
-    '''
-    return self._statuses_count
-
-  def SetStatusesCount(self, count):
-    '''Set the status update count for this user.
-
-    @param count: The number of updates for this user.
-    '''
-    self._statuses_count = count
-
-  statuses_count = property(GetStatusesCount, SetStatusesCount,
-                  doc='The number of updates for this user.')
-
-  def GetFavouritesCount(self):
-    '''Get the number of favourites for this user.
-    
-    @returns: The number of favourites for this user.
-    '''
-    return self._favourites_count
-
-  def SetFavouritesCount(self, count):
-    '''Set the favourite count for this user.
-
-    @param count: The number of favourites for this user.
-    '''
-    self._favourites_count = count
-
-  favourites_count = property(GetFavouritesCount, SetFavouritesCount,
-                  doc='The number of favourites for this user.')
-
-  def __ne__(self, other):
-    return not self.__eq__(other)
-
-  def __eq__(self, other):
-    try:
-      return other and \
-             self.id == other.id and \
-             self.name == other.name and \
-             self.screen_name == other.screen_name and \
-             self.location == other.location and \
-             self.description == other.description and \
-             self.profile_image_url == other.profile_image_url and \
-             self.profile_background_tile == other.profile_background_tile and \
-             self.profile_background_image_url == other.profile_background_image_url and \
-             self.profile_sidebar_fill_color == other.profile_sidebar_fill_color and \
-             self.profile_background_color == other.profile_background_color and \
-             self.profile_link_color == other.profile_link_color and \
-             self.profile_text_color == other.profile_text_color and \
-             self.protected == other.protected and \
-             self.utc_offset == other.utc_offset and \
-             self.time_zone == other.time_zone and \
-             self.url == other.url and \
-             self.statuses_count == other.statuses_count and \
-             self.followers_count == other.followers_count and \
-             self.favourites_count == other.favourites_count and \
-             self.friends_count == other.friends_count and \
-             self.status == other.status
-    except AttributeError:
-      return False
-
-  def __str__(self):
-    '''A string representation of this twitter.User instance.
-
-    The return value is the same as the JSON string representation.
-
-    @returns: A string representation of this twitter.User instance.
-    '''
-    return self.AsJsonString()
-
-  def AsJsonString(self):
-    '''A JSON string representation of this twitter.User instance.
-
-    @returns: A JSON string representation of this twitter.User instance
-   '''
-    return json.dumps(self.AsDict(), sort_keys=True)
-
-  def AsDict(self):
-    '''A dict representation of this twitter.User instance.
-
-    The return value uses the same key names as the JSON representation.
-
-    @return: A dict representing this twitter.User instance
-    '''
-    data = {}
-    if self.id:
-      data['id'] = self.id
-    if self.name:
-      data['name'] = self.name
-    if self.screen_name:
-      data['screen_name'] = self.screen_name
-    if self.location:
-      data['location'] = self.location
-    if self.description:
-      data['description'] = self.description
-    if self.profile_image_url:
-      data['profile_image_url'] = self.profile_image_url
-    if self.profile_background_tile is not None:
-      data['profile_background_tile'] = self.profile_background_tile
-    if self.profile_background_image_url:
-      data['profile_sidebar_fill_color'] = self.profile_background_image_url
-    if self.profile_background_color:
-      data['profile_background_color'] = self.profile_background_color
-    if self.profile_link_color:
-      data['profile_link_color'] = self.profile_link_color
-    if self.profile_text_color:
-      data['profile_text_color'] = self.profile_text_color
-    if self.protected is not None:
-      data['protected'] = self.protected
-    if self.utc_offset:
-      data['utc_offset'] = self.utc_offset
-    if self.time_zone:
-      data['time_zone'] = self.time_zone
-    if self.url:
-      data['url'] = self.url
-    if self.status:
-      data['status'] = self.status.AsDict()
-    if self.friends_count:
-      data['friends_count'] = self.friends_count
-    if self.followers_count:
-      data['followers_count'] = self.followers_count
-    if self.statuses_count:
-      data['statuses_count'] = self.statuses_count
-    if self.favourites_count:
-      data['favourites_count'] = self.favourites_count
-    return data
-
-  @staticmethod
-  def NewFromJsonDict(data):
-    '''Create a new instance based on a JSON dict.
-
-    @param data: A JSON dict, as converted from the JSON in the twitter API
-    @returns: A twitter.User instance
-    '''
-    if 'status' in data:
-      status = Status.NewFromJsonDict(data['status'])
-    else:
-      status = None
-    return User(id=data.get('id', None),
-                name=data.get('name', None),
-                screen_name=data.get('screen_name', None),
-                location=data.get('location', None),
-                description=data.get('description', None),
-                statuses_count=data.get('statuses_count', None),
-                followers_count=data.get('followers_count', None),
-                favourites_count=data.get('favourites_count', None),
-                friends_count=data.get('friends_count', None),
-                profile_image_url=data.get('profile_image_url', None),
-                profile_background_tile = data.get('profile_background_tile', None),
-                profile_background_image_url = data.get('profile_background_image_url', None),
-                profile_sidebar_fill_color = data.get('profile_sidebar_fill_color', None),
-                profile_background_color = data.get('profile_background_color', None),
-                profile_link_color = data.get('profile_link_color', None),
-                profile_text_color = data.get('profile_text_color', None),
-                protected = data.get('protected', None),
-                utc_offset = data.get('utc_offset', None),
-                time_zone = data.get('time_zone', None),
-                url=data.get('url', None),
-                status=status)
+    '''A class representing the User structure used by the twitter API.
+
+    The User structure exposes the following properties:
+
+        - user.id
+        - user.name
+        - user.screen_name
+        - user.location
+        - user.description
+        - user.profile_image_url
+        - user.profile_background_tile
+        - user.profile_background_image_url
+        - user.profile_sidebar_fill_color
+        - user.profile_background_color
+        - user.profile_link_color
+        - user.profile_text_color
+        - user.protected
+        - user.utc_offset
+        - user.time_zone
+        - user.url
+        - user.status
+        - user.statuses_count
+        - user.followers_count
+        - user.friends_count
+        - user.favourites_count
+      '''
+
+    def __init__(self,
+                   id=None,
+                   name=None,
+                   screen_name=None,
+                   location=None,
+                   description=None,
+                   profile_image_url=None,
+                   profile_background_tile=None,
+                   profile_background_image_url=None,
+                   profile_sidebar_fill_color=None,
+                   profile_background_color=None,
+                   profile_link_color=None,
+                   profile_text_color=None,
+                   protected=None,
+                   utc_offset=None,
+                   time_zone=None,
+                   followers_count=None,
+                   friends_count=None,
+                   statuses_count=None,
+                   favourites_count=None,
+                   url=None,
+                   status=None):
+        self.id = id
+        self.name = name
+        self.screen_name = screen_name
+        self.location = location
+        self.description = description
+        self.profile_image_url = profile_image_url
+        self.profile_background_tile = profile_background_tile
+        self.profile_background_image_url = profile_background_image_url
+        self.profile_sidebar_fill_color = profile_sidebar_fill_color
+        self.profile_background_color = profile_background_color
+        self.profile_link_color = profile_link_color
+        self.profile_text_color = profile_text_color
+        self.protected = protected
+        self.utc_offset = utc_offset
+        self.time_zone = time_zone
+        self.followers_count = followers_count
+        self.friends_count = friends_count
+        self.statuses_count = statuses_count
+        self.favourites_count = favourites_count
+        self.url = url
+        self.status = status
+
+    def GetId(self):
+        '''Get the unique id of this user.
+
+        @returns: The unique id of this user
+        '''
+        return self._id
+
+    def SetId(self, id):
+        '''Set the unique id of this user.
+
+        @param: id: The unique id of this user.
+        '''
+        self._id = id
+
+        id = property(GetId, SetId,
+                    doc='The unique id of this user.')
+
+    def GetName(self):
+        '''Get the real name of this user.
+
+        @returns: The real name of this user
+        '''
+        return self._name
+
+    def SetName(self, name):
+        '''Set the real name of this user.
+
+        @param name: The real name of this user
+        '''
+        self._name = name
+
+        name = property(GetName, SetName,
+                      doc='The real name of this user.')
+
+    def GetScreenName(self):
+        '''Get the short username of this user.
+
+        @returns: The short username of this user
+        '''
+        return self._screen_name
+
+    def SetScreenName(self, screen_name):
+        '''Set the short username of this user.
+
+        @param screen_name: the short username of this user
+        '''
+        self._screen_name = screen_name
+
+        screen_name = property(GetScreenName, SetScreenName,
+                             doc='The short username of this user.')
+
+    def GetLocation(self):
+        '''Get the geographic location of this user.
+
+        @returns: The geographic location of this user
+        '''
+        return self._location
+
+    def SetLocation(self, location):
+        '''Set the geographic location of this user.
+
+        @param location: The geographic location of this user
+        '''
+        self._location = location
+
+        location = property(GetLocation, SetLocation,
+                          doc='The geographic location of this user.')
+
+    def GetDescription(self):
+        '''Get the short text description of this user.
+
+        @returns: The short text description of this user
+        '''
+        return self._description
+
+    def SetDescription(self, description):
+        '''Set the short text description of this user.
+
+        @param description: The short text description of this user
+        '''
+        self._description = description
+
+        description = property(GetDescription, SetDescription,
+                             doc='The short text description of this user.')
+
+    def GetUrl(self):
+        '''Get the homepage url of this user.
+
+        @returns: The homepage url of this user
+        '''
+        return self._url
+
+    def SetUrl(self, url):
+        '''Set the homepage url of this user.
+
+        @param url: The homepage url of this user
+        '''
+        self._url = url
+
+        url = property(GetUrl, SetUrl,
+                     doc='The homepage url of this user.')
+
+    def GetProfileImageUrl(self):
+        '''Get the url of the thumbnail of this user.
+
+        @returns: The url of the thumbnail of this user
+        '''
+        return self._profile_image_url
+
+    def SetProfileImageUrl(self, profile_image_url):
+        '''Set the url of the thumbnail of this user.
+
+        @param profile_image_url: The url of the thumbnail of this user
+        '''
+        self._profile_image_url = profile_image_url
+
+        profile_image_url= property(GetProfileImageUrl, SetProfileImageUrl,
+                                  doc='The url of the thumbnail of this user.')
+
+    def GetProfileBackgroundTile(self):
+        '''Boolean for whether to tile the profile background image.
+
+        @returns: True if the background is to be tiled, False if not, None if
+                  unset.
+        '''
+        return self._profile_background_tile
+
+    def SetProfileBackgroundTile(self, profile_background_tile):
+        '''Set the boolean flag for whether to tile the profile background
+        image.
+
+        @param profile_background_tile: Boolean flag for whether to tile or not
+        '''
+        self._profile_background_tile = profile_background_tile
+
+        profile_background_tile = property(GetProfileBackgroundTile,
+                                           SetProfileBackgroundTile,
+                       doc='Boolean for whether to tile the background image.')
+
+    def GetProfileBackgroundImageUrl(self):
+        return self._profile_background_image_url
+
+    def SetProfileBackgroundImageUrl(self, profile_background_image_url):
+        self._profile_background_image_url = profile_background_image_url
+
+        profile_background_image_url = property(GetProfileBackgroundImageUrl,
+                                                SetProfileBackgroundImageUrl,
+                         doc='The url of the profile background of this user.')
+
+    def GetProfileSidebarFillColor(self):
+        return self._profile_sidebar_fill_color
+
+    def SetProfileSidebarFillColor(self, profile_sidebar_fill_color):
+        self._profile_sidebar_fill_color = profile_sidebar_fill_color
+
+        profile_sidebar_fill_color = property(GetProfileSidebarFillColor,
+                                              SetProfileSidebarFillColor)
+
+    def GetProfileBackgroundColor(self):
+        return self._profile_background_color
+
+    def SetProfileBackgroundColor(self, profile_background_color):
+        self._profile_background_color = profile_background_color
+
+        profile_background_color = property(GetProfileBackgroundColor,
+                                              SetProfileBackgroundColor)
+
+    def GetProfileLinkColor(self):
+        return self._profile_link_color
+
+    def SetProfileLinkColor(self, profile_link_color):
+        self._profile_link_color = profile_link_color
+
+        profile_link_color = property(GetProfileLinkColor, SetProfileLinkColor)
+
+    def GetProfileTextColor(self):
+        return self._profile_text_color
+
+    def SetProfileTextColor(self, profile_text_color):
+        self._profile_text_color = profile_text_color
+
+        profile_text_color = property(GetProfileTextColor, SetProfileTextColor)
+
+    def GetProtected(self):
+        return self._protected
+
+    def SetProtected(self, protected):
+        self._protected = protected
+
+        protected = property(GetProtected, SetProtected)
+
+    def GetUtcOffset(self):
+        return self._utc_offset
+
+    def SetUtcOffset(self, utc_offset):
+        self._utc_offset = utc_offset
+
+        utc_offset = property(GetUtcOffset, SetUtcOffset)
+
+    def GetTimeZone(self):
+        '''Returns the current time zone string for the user.
+
+        @returns: The descriptive time zone string for the user.
+        '''
+        return self._time_zone
+
+    def SetTimeZone(self, time_zone):
+        '''Sets the user's time zone string.
+
+        @param time_zone: The descriptive time zone to assign for the user.
+        '''
+        self._time_zone = time_zone
+
+        time_zone = property(GetTimeZone, SetTimeZone)
+
+    def GetStatus(self):
+        '''Get the latest twitter.Status of this user.
+
+        @returns: The latest twitter.Status of this user
+        '''
+        return self._status
+
+    def SetStatus(self, status):
+        '''Set the latest twitter.Status of this user.
+
+        @param status: The latest twitter.Status of this user
+        '''
+        self._status = status
+
+        status = property(GetStatus, SetStatus,
+                      doc='The latest twitter.Status of this user.')
+
+    def GetFriendsCount(self):
+        '''Get the friend count for this user.
+
+        @returns: The number of users this user has befriended.
+        '''
+        return self._friends_count
+
+    def SetFriendsCount(self, count):
+        '''Set the friend count for this user.
+
+        @param count: The number of users this user has befriended.
+        '''
+        self._friends_count = count
+
+        friends_count = property(GetFriendsCount, SetFriendsCount,
+                      doc='The number of friends for this user.')
+
+    def GetFollowersCount(self):
+        '''Get the follower count for this user.
+
+        @returns: The number of users following this user.
+        '''
+        return self._followers_count
+
+    def SetFollowersCount(self, count):
+        '''Set the follower count for this user.
+
+        @param count: The number of users following this user.
+        '''
+        self._followers_count = count
+
+        followers_count = property(GetFollowersCount, SetFollowersCount,
+                      doc='The number of users following this user.')
+
+    def GetStatusesCount(self):
+        '''Get the number of status updates for this user.
+
+        @returns: The number of status updates for this user.
+        '''
+        return self._statuses_count
+
+    def SetStatusesCount(self, count):
+        '''Set the status update count for this user.
+
+        @param count: The number of updates for this user.
+        '''
+        self._statuses_count = count
+
+        statuses_count = property(GetStatusesCount, SetStatusesCount,
+                      doc='The number of updates for this user.')
+
+    def GetFavouritesCount(self):
+        '''Get the number of favourites for this user.
+
+        @returns: The number of favourites for this user.
+        '''
+        return self._favourites_count
+
+    def SetFavouritesCount(self, count):
+        '''Set the favourite count for this user.
+
+        @param count: The number of favourites for this user.
+        '''
+        self._favourites_count = count
+
+        favourites_count = property(GetFavouritesCount, SetFavouritesCount,
+                      doc='The number of favourites for this user.')
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
+    def __eq__(self, other):
+        try:
+            return other and \
+                self.id == other.id and \
+                self.name == other.name and \
+                self.screen_name == other.screen_name and \
+                self.location == other.location and \
+                self.description == other.description and \
+                self.profile_image_url == other.profile_image_url and \
+                self.profile_background_tile == \
+                                            other.profile_background_tile and \
+                self.profile_background_image_url == \
+                                       other.profile_background_image_url and \
+                self.profile_sidebar_fill_color == \
+                                         other.profile_sidebar_fill_color and \
+                self.profile_background_color == \
+                                           other.profile_background_color and \
+                self.profile_link_color == other.profile_link_color and \
+                self.profile_text_color == other.profile_text_color and \
+                self.protected == other.protected and \
+                self.utc_offset == other.utc_offset and \
+                self.time_zone == other.time_zone and \
+                self.url == other.url and \
+                self.statuses_count == other.statuses_count and \
+                self.followers_count == other.followers_count and \
+                self.favourites_count == other.favourites_count and \
+                self.friends_count == other.friends_count and \
+                self.status == other.status
+        except AttributeError:
+            return False
+
+    def __str__(self):
+        '''A string representation of this twitter.User instance.
+
+        The return value is the same as the JSON string representation.
+
+        @returns: A string representation of this twitter.User instance.
+        '''
+        return self.AsJsonString()
+
+    def AsJsonString(self):
+        '''A JSON string representation of this twitter.User instance.
+
+        @returns: A JSON string representation of this twitter.User instance
+        '''
+        return json.dumps(self.AsDict(), sort_keys=True)
+
+    def AsDict(self):
+        '''A dict representation of this twitter.User instance.
+
+        The return value uses the same key names as the JSON representation.
+
+        @return: A dict representing this twitter.User instance
+        '''
+        data = {}
+        if self.id:
+            data['id'] = self.id
+        if self.name:
+            data['name'] = self.name
+        if self.screen_name:
+            data['screen_name'] = self.screen_name
+        if self.location:
+            data['location'] = self.location
+        if self.description:
+            data['description'] = self.description
+        if self.profile_image_url:
+            data['profile_image_url'] = self.profile_image_url
+        if self.profile_background_tile is not None:
+            data['profile_background_tile'] = self.profile_background_tile
+        if self.profile_background_image_url:
+            data['profile_sidebar_fill_color'] = \
+                                         self.profile_background_image_url
+        if self.profile_background_color:
+            data['profile_background_color'] = self.profile_background_color
+        if self.profile_link_color:
+            data['profile_link_color'] = self.profile_link_color
+        if self.profile_text_color:
+            data['profile_text_color'] = self.profile_text_color
+        if self.protected is not None:
+            data['protected'] = self.protected
+        if self.utc_offset:
+            data['utc_offset'] = self.utc_offset
+        if self.time_zone:
+            data['time_zone'] = self.time_zone
+        if self.url:
+            data['url'] = self.url
+        if self.status:
+            data['status'] = self.status.AsDict()
+        if self.friends_count:
+            data['friends_count'] = self.friends_count
+        if self.followers_count:
+            data['followers_count'] = self.followers_count
+        if self.statuses_count:
+            data['statuses_count'] = self.statuses_count
+        if self.favourites_count:
+            data['favourites_count'] = self.favourites_count
+        return data
+
+    @staticmethod
+    def NewFromJsonDict(data):
+        '''Create a new instance based on a JSON dict.
+
+        @param data: A JSON dict, as converted from the JSON in the twitter API
+        @returns: A twitter.User instance
+        '''
+        if 'status' in data:
+            status = Status.NewFromJsonDict(data['status'])
+        else:
+            status = None
+        return User(id=data.get('id', None),
+                    name=data.get('name', None),
+                    screen_name=data.get('screen_name', None),
+                    location=data.get('location', None),
+                    description=data.get('description', None),
+                    statuses_count=data.get('statuses_count', None),
+                    followers_count=data.get('followers_count', None),
+                    favourites_count=data.get('favourites_count', None),
+                    friends_count=data.get('friends_count', None),
+                    profile_image_url=data.get('profile_image_url', None),
+                    profile_background_tile = data.get(
+                                              'profile_background_tile', None),
+                    profile_background_image_url = data.get(
+                                         'profile_background_image_url', None),
+                    profile_sidebar_fill_color = data.get(
+                                           'profile_sidebar_fill_color', None),
+                    profile_background_color = data.get(
+                                             'profile_background_color', None),
+                    profile_link_color = data.get('profile_link_color', None),
+                    profile_text_color = data.get('profile_text_color', None),
+                    protected = data.get('protected', None),
+                    utc_offset = data.get('utc_offset', None),
+                    time_zone = data.get('time_zone', None),
+                    url=data.get('url', None),
+                    status=status)
+
 
 class DirectMessage(object):
-  '''A class representing the DirectMessage structure used by the twitter API.
-
-  The DirectMessage structure exposes the following properties:
-
-    - direct_message.id
-    - direct_message.created_at
-    - direct_message.created_at_in_seconds # read only
-    - direct_message.sender_id
-    - direct_message.sender_screen_name
-    - direct_message.recipient_id
-    - direct_message.recipient_screen_name
-    - direct_message.text
-  '''
-
-  def __init__(self,
-               id=None,
-               created_at=None,
-               sender_id=None,
-               sender_screen_name=None,
-               recipient_id=None,
-               recipient_screen_name=None,
-               text=None):
-    '''An object to hold a Twitter direct message.
-
-    This class is normally instantiated by the twitter.Api class and
-    returned in a sequence.
-
-    Note: Dates are posted in the form "Sat Jan 27 04:17:38 +0000 2007"
-
-    @param id: The unique id of this direct message
-    @param created_at: The time this direct message was posted
-    @param sender_id: The id of the twitter user that sent this message
-    @param sender_screen_name: The name of the twitter user that sent this message
-    @param recipient_id: The id of the twitter that received this message
-    @param recipient_screen_name: The name of the twitter that received this message
-    @param text: The text of this direct message
-    '''
-    self.id = id
-    self.created_at = created_at
-    self.sender_id = sender_id
-    self.sender_screen_name = sender_screen_name
-    self.recipient_id = recipient_id
-    self.recipient_screen_name = recipient_screen_name
-    self.text = text
-
-  def GetId(self):
-    '''Get the unique id of this direct message.
-
-    @returns: The unique id of this direct message
-    '''
-    return self._id
-
-  def SetId(self, id):
-    '''Set the unique id of this direct message.
-
-    @param id: The unique id of this direct message
-    '''
-    self._id = id
-
-  id = property(GetId, SetId,
-                doc='The unique id of this direct message.')
-
-  def GetCreatedAt(self):
-    '''Get the time this direct message was posted.
-
-    @returns: The time this direct message was posted
-    '''
-    return self._created_at
-
-  def SetCreatedAt(self, created_at):
-    '''Set the time this direct message was posted.
-
-    @param created_at: The time this direct message was created
-    '''
-    self._created_at = created_at
-
-  created_at = property(GetCreatedAt, SetCreatedAt,
-                        doc='The time this direct message was posted.')
-
-  def GetCreatedAtInSeconds(self):
-    '''Get the time this direct message was posted, in seconds since the epoch.
-
-    @returns: The time this direct message was posted, in seconds since the epoch.
-    '''
-    return calendar.timegm(rfc822.parsedate(self.created_at))
-
-  created_at_in_seconds = property(GetCreatedAtInSeconds,
-                                   doc="The time this direct message was "
-                                       "posted, in seconds since the epoch")
-
-  def GetSenderId(self):
-    '''Get the unique sender id of this direct message.
-
-    @returns: The unique sender id of this direct message
-    '''
-    return self._sender_id
-
-  def SetSenderId(self, sender_id):
-    '''Set the unique sender id of this direct message.
-
-    @param sender_id: The unique sender id of this direct message
-    '''
-    self._sender_id = sender_id
-
-  sender_id = property(GetSenderId, SetSenderId,
-                doc='The unique sender id of this direct message.')
-
-  def GetSenderScreenName(self):
-    '''Get the unique sender screen name of this direct message.
-
-    @returns: The unique sender screen name of this direct message
-    '''
-    return self._sender_screen_name
-
-  def SetSenderScreenName(self, sender_screen_name):
-    '''Set the unique sender screen name of this direct message.
-
-    @param sender_screen_name: The unique sender screen name of this direct
-        message
-    '''
-    self._sender_screen_name = sender_screen_name
-
-  sender_screen_name = property(GetSenderScreenName, SetSenderScreenName,
-                doc='The unique sender screen name of this direct message.')
-
-  def GetRecipientId(self):
-    '''Get the unique recipient id of this direct message.
-
-    @returns: The unique recipient id of this direct message
-    '''
-    return self._recipient_id
-
-  def SetRecipientId(self, recipient_id):
-    '''Set the unique recipient id of this direct message.
-
-    @param recipient id: The unique recipient id of this direct message
-    '''
-    self._recipient_id = recipient_id
-
-  recipient_id = property(GetRecipientId, SetRecipientId,
-                doc='The unique recipient id of this direct message.')
-
-  def GetRecipientScreenName(self):
-    '''Get the unique recipient screen name of this direct message.
-
-    @returns: The unique recipient screen name of this direct message
-    '''
-    return self._recipient_screen_name
-
-  def SetRecipientScreenName(self, recipient_screen_name):
-    '''Set the unique recipient screen name of this direct message.
-
-    @param recipient_screen_name: The unique recipient screen name of this direct message
-    '''
-    self._recipient_screen_name = recipient_screen_name
-
-  recipient_screen_name = property(GetRecipientScreenName, SetRecipientScreenName,
+    '''A class representing the DirectMessage structure used by the twitter API
+
+    The DirectMessage structure exposes the following properties:
+
+        - direct_message.id
+        - direct_message.created_at
+        - direct_message.created_at_in_seconds # read only
+        - direct_message.sender_id
+        - direct_message.sender_screen_name
+        - direct_message.recipient_id
+        - direct_message.recipient_screen_name
+        - direct_message.text
+    '''
+
+    def __init__(self,
+                   id=None,
+                   created_at=None,
+                   sender_id=None,
+                   sender_screen_name=None,
+                   recipient_id=None,
+                   recipient_screen_name=None,
+                   text=None):
+        '''An object to hold a Twitter direct message.
+
+        This class is normally instantiated by the twitter.Api class and
+        returned in a sequence.
+
+        Note: Dates are posted in the form "Sat Jan 27 04:17:38 +0000 2007"
+
+        @param id: The unique id of this direct message
+        @param created_at: The time this direct message was posted
+        @param sender_id: The id of the twitter user that sent this message
+        @param sender_screen_name: The name of the twitter user that sent this
+                                   message
+        @param recipient_id: The id of the twitter that received this message
+        @param recipient_screen_name: The name of the twitter that received
+                                      this message
+        @param text: The text of this direct message
+        '''
+        self.id = id
+        self.created_at = created_at
+        self.sender_id = sender_id
+        self.sender_screen_name = sender_screen_name
+        self.recipient_id = recipient_id
+        self.recipient_screen_name = recipient_screen_name
+        self.text = text
+
+    def GetId(self):
+        '''Get the unique id of this direct message.
+
+        @returns: The unique id of this direct message
+        '''
+        return self._id
+
+    def SetId(self, id):
+        '''Set the unique id of this direct message.
+
+        @param id: The unique id of this direct message
+        '''
+        self._id = id
+
+        id = property(GetId, SetId,
+                    doc='The unique id of this direct message.')
+
+    def GetCreatedAt(self):
+        '''Get the time this direct message was posted.
+
+        @returns: The time this direct message was posted
+        '''
+        return self._created_at
+
+    def SetCreatedAt(self, created_at):
+        '''Set the time this direct message was posted.
+
+        @param created_at: The time this direct message was created
+        '''
+        self._created_at = created_at
+
+        created_at = property(GetCreatedAt, SetCreatedAt,
+                            doc='The time this direct message was posted.')
+
+    def GetCreatedAtInSeconds(self):
+        '''Get the time this direct message was posted, in seconds since the
+        epoch.
+
+        @returns: The time this direct message was posted, in seconds since the
+                  epoch.
+        '''
+        return calendar.timegm(rfc822.parsedate(self.created_at))
+
+        created_at_in_seconds = property(GetCreatedAtInSeconds,
+                                       doc="The time this direct message was "
+                                          "posted, in seconds since the epoch")
+
+    def GetSenderId(self):
+        '''Get the unique sender id of this direct message.
+
+        @returns: The unique sender id of this direct message
+        '''
+        return self._sender_id
+
+    def SetSenderId(self, sender_id):
+        '''Set the unique sender id of this direct message.
+
+        @param sender_id: The unique sender id of this direct message
+        '''
+        self._sender_id = sender_id
+
+        sender_id = property(GetSenderId, SetSenderId,
+                    doc='The unique sender id of this direct message.')
+
+    def GetSenderScreenName(self):
+        '''Get the unique sender screen name of this direct message.
+
+        @returns: The unique sender screen name of this direct message
+        '''
+        return self._sender_screen_name
+
+    def SetSenderScreenName(self, sender_screen_name):
+        '''Set the unique sender screen name of this direct message.
+
+        @param sender_screen_name: The unique sender screen name of this direct
+            message
+        '''
+        self._sender_screen_name = sender_screen_name
+
+        sender_screen_name = property(GetSenderScreenName, SetSenderScreenName,
+                   doc='The unique sender screen name of this direct message.')
+
+    def GetRecipientId(self):
+        '''Get the unique recipient id of this direct message.
+
+        @returns: The unique recipient id of this direct message
+        '''
+        return self._recipient_id
+
+    def SetRecipientId(self, recipient_id):
+        '''Set the unique recipient id of this direct message.
+
+        @param recipient id: The unique recipient id of this direct message
+        '''
+        self._recipient_id = recipient_id
+
+        recipient_id = property(GetRecipientId, SetRecipientId,
+                    doc='The unique recipient id of this direct message.')
+
+    def GetRecipientScreenName(self):
+        '''Get the unique recipient screen name of this direct message.
+
+        @returns: The unique recipient screen name of this direct message
+        '''
+        return self._recipient_screen_name
+
+    def SetRecipientScreenName(self, recipient_screen_name):
+        '''Set the unique recipient screen name of this direct message.
+
+        @param recipient_screen_name: The unique recipient screen name of this
+                                      direct message
+        '''
+        self._recipient_screen_name = recipient_screen_name
+
+        recipient_screen_name = property(GetRecipientScreenName,
+                                         SetRecipientScreenName,
                 doc='The unique recipient screen name of this direct message.')
 
-  def GetText(self):
-    '''Get the text of this direct message.
-
-    @returns: The text of this direct message.
-    '''
-    return self._text
-
-  def SetText(self, text):
-    '''Set the text of this direct message.
-
-    @param text: The text of this direct message
-    '''
-    self._text = text
-
-  text = property(GetText, SetText,
-                  doc='The text of this direct message')
-
-  def __ne__(self, other):
-    return not self.__eq__(other)
-
-  def __eq__(self, other):
-    try:
-      return other and \
-          self.id == other.id and \
-          self.created_at == other.created_at and \
-          self.sender_id == other.sender_id and \
-          self.sender_screen_name == other.sender_screen_name and \
-          self.recipient_id == other.recipient_id and \
-          self.recipient_screen_name == other.recipient_screen_name and \
-          self.text == other.text
-    except AttributeError:
-      return False
-
-  def __str__(self):
-    '''A string representation of this twitter.DirectMessage instance.
-
-    The return value is the same as the JSON string representation.
-
-    @returns: A string representation of this twitter.DirectMessage instance.
-    '''
-    return self.AsJsonString()
-
-  def AsJsonString(self):
-    '''A JSON string representation of this twitter.DirectMessage instance.
-
-    @returns: A JSON string representation of this twitter.DirectMessage instance
-   '''
-    return json.dumps(self.AsDict(), sort_keys=True)
-
-  def AsDict(self):
-    '''A dict representation of this twitter.DirectMessage instance.
-
-    The return value uses the same key names as the JSON representation.
-
-    @returns: A dict representing this twitter.DirectMessage instance
-    '''
-    data = {}
-    if self.id:
-      data['id'] = self.id
-    if self.created_at:
-      data['created_at'] = self.created_at
-    if self.sender_id:
-      data['sender_id'] = self.sender_id
-    if self.sender_screen_name:
-      data['sender_screen_name'] = self.sender_screen_name
-    if self.recipient_id:
-      data['recipient_id'] = self.recipient_id
-    if self.recipient_screen_name:
-      data['recipient_screen_name'] = self.recipient_screen_name
-    if self.text:
-      data['text'] = self.text
-    return data
-
-  @staticmethod
-  def NewFromJsonDict(data):
-    '''Create a new instance based on a JSON dict.
-
-    @param data: A JSON dict, as converted from the JSON in the twitter API
-    @returns: A twitter.DirectMessage instance
-    '''
-    return DirectMessage(created_at=data.get('created_at', None),
-                         recipient_id=data.get('recipient_id', None),
-                         sender_id=data.get('sender_id', None),
-                         text=data.get('text', None),
-                         sender_screen_name=data.get('sender_screen_name', None),
-                         id=data.get('id', None),
-                         recipient_screen_name=data.get('recipient_screen_name', None))
+    def GetText(self):
+        '''Get the text of this direct message.
+
+        @returns: The text of this direct message.
+        '''
+        return self._text
+
+    def SetText(self, text):
+        '''Set the text of this direct message.
+
+        @param text: The text of this direct message
+        '''
+        self._text = text
+
+        text = property(GetText, SetText,
+                      doc='The text of this direct message')
+
+    def __ne__(self, other):
+        return not self.__eq__(other)
+
+    def __eq__(self, other):
+        try:
+            return other and \
+                self.id == other.id and \
+                self.created_at == other.created_at and \
+                self.sender_id == other.sender_id and \
+                self.sender_screen_name == other.sender_screen_name and \
+                self.recipient_id == other.recipient_id and \
+                self.recipient_screen_name == other.recipient_screen_name and \
+                self.text == other.text
+        except AttributeError:
+            return False
+
+    def __str__(self):
+        '''A string representation of this twitter.DirectMessage instance.
+
+        The return value is the same as the JSON string representation.
+
+        @returns: A string representation of this twitter.DirectMessage
+                  instance.
+        '''
+        return self.AsJsonString()
+
+    def AsJsonString(self):
+        '''A JSON string representation of this twitter.DirectMessage instance.
+
+        @returns: A JSON string representation of this twitter.DirectMessage
+                  instance
+        '''
+        return json.dumps(self.AsDict(), sort_keys=True)
+
+    def AsDict(self):
+        '''A dict representation of this twitter.DirectMessage instance.
+
+        The return value uses the same key names as the JSON representation.
+
+        @returns: A dict representing this twitter.DirectMessage instance
+        '''
+        data = {}
+        if self.id:
+            data['id'] = self.id
+        if self.created_at:
+            data['created_at'] = self.created_at
+        if self.sender_id:
+            data['sender_id'] = self.sender_id
+        if self.sender_screen_name:
+            data['sender_screen_name'] = self.sender_screen_name
+        if self.recipient_id:
+            data['recipient_id'] = self.recipient_id
+        if self.recipient_screen_name:
+            data['recipient_screen_name'] = self.recipient_screen_name
+        if self.text:
+            data['text'] = self.text
+        return data
+
+    @staticmethod
+    def NewFromJsonDict(data):
+        '''Create a new instance based on a JSON dict.
+
+        @param data: A JSON dict, as converted from the JSON in the twitter API
+        @returns: A twitter.DirectMessage instance
+        '''
+        return DirectMessage(created_at=data.get('created_at', None),
+                             recipient_id=data.get('recipient_id', None),
+                             sender_id=data.get('sender_id', None),
+                             text=data.get('text', None),
+                             sender_screen_name=data.get('sender_screen_name',
+                                                          None),
+                             id=data.get('id', None),
+                             recipient_screen_name=data.get(
+                                               'recipient_screen_name', None))
+
 
 class Api(object):
-  '''A python interface into the Twitter API
-
-  By default, the Api caches results for 1 minute.
-
-  Example usage:
-
-      - To create an instance of the twitter.Api class, with no authentication:
-
-          >>> import twitter
-          >>> api = twitter.Api()
-
-      - To fetch the most recently posted public twitter status messages:
-
-          >>> statuses = api.GetPublicTimeline()
-          >>> print [s.user.name for s in statuses]
-          [u'DeWitt', u'Kesuke Miyagi', u'ev', u'Buzz Andersen', u'Biz Stone'] #...
+    '''A python interface into the Twitter API
+
+    By default, the Api caches results for 1 minute.
+
+    Example usage:
+
+        - To create an instance of the twitter.Api class, with no
+          authentication:
+            >>> import twitter
+            >>> api = twitter.Api()
+
+        - To fetch the most recently posted public twitter status messages:
+
+            >>> statuses = api.GetPublicTimeline()
+            >>> print [s.user.name for s in statuses]
+           [u'DeWitt', u'Kesuke Miyagi', u'ev', u'Buzz Andersen', u'Biz Stone']
+             #... (<<< Shouldn't this be actually removed?? -Nimit *TODO*)
 
       - To fetch a single user's public status messages, where "user" is either
-        a Twitter "short name" or their user id.
-
-          >>> statuses = api.GetUserTimeline(user)
-          >>> print [s.text for s in statuses]
-
-      - To use authentication, instantiate the twitter.Api class with a
-        username and password:
-
-          >>> api = twitter.Api(username='twitter user', password='twitter pass')
-
-      - To fetch your friends (after being authenticated):
-
-          >>> users = api.GetFriends()
-          >>> print [u.name for u in users]
-
-      - To post a twitter status message (after being authenticated):
-
-          >>> status = api.PostUpdate('I love python-twitter!')
-          >>> print status.text
-          I love python-twitter!
-
-      - There are many other methods, including:
-
-          >>> api.PostUpdates(status)
-          >>> api.PostDirectMessage(user, text)
-          >>> api.GetUser(user)
-          >>> api.GetReplies()
-          >>> api.GetUserTimeline(user)
-          >>> api.GetStatus(id)
-          >>> api.DestroyStatus(id)
-          >>> api.GetFriendsTimeline(user)
-          >>> api.GetFriends(user)
-          >>> api.GetFollowers()
-          >>> api.GetFeatured()
-          >>> api.GetDirectMessages()
-          >>> api.PostDirectMessage(user, text)
-          >>> api.DestroyDirectMessage(id)
-          >>> api.DestroyFriendship(user)
-          >>> api.CreateFriendship(user)
-          >>> api.GetUserByEmail(email)
-          >>> api.VerifyCredentials()
-  '''
-
-  DEFAULT_CACHE_TIMEOUT = 60 # cache for 1 minute
-
-  _API_REALM = 'Twitter API'
-
-  def __init__(self,
-               username=None,
-               password=None,
-               input_encoding=None,
-               request_headers=None,
-               cache=DEFAULT_CACHE,
-               shortner=None,
-               base_url=None,
-               use_gzip_compression=False):
-    '''Instantiate a new twitter.Api object.
-
-    @param username: The username of the twitter account.  [optional]
-    @param password: The password for the twitter account. [optional]
-    @param input_encoding: The encoding used to encode input strings.
-        [optional]
-    @param request_header: A dictionary of additional HTTP request headers.
-        [optional]
-    @param cache: The cache instance to use. Defaults to DEFAULT_CACHE.
-        Use None to disable caching. [optional]
-    @param shortner: The shortner instance to use.  Defaults to None.
-        See shorten_url.py for an example shortner. [optional]
-    @param base_url: The base URL to use to contact the Twitter API.
-        Defaults to https://twitter.com. [optional]
-    @param use_gzip_compression: Set to True to tell enable gzip compression
-        for any call made to Twitter.  Defaults to False. [optional]
-    '''
-    self.SetCache(cache)
-    self._urllib = urllib2
-    self._cache_timeout = Api.DEFAULT_CACHE_TIMEOUT
-    self._InitializeRequestHeaders(request_headers)
-    self._InitializeUserAgent()
-    self._InitializeDefaultParameters()
-    self._input_encoding = input_encoding
-    self._use_gzip = use_gzip_compression
-    self.SetCredentials(username, password)
-    if base_url is None:
-      self.base_url = 'https://twitter.com'
-    else:
-      self.base_url = base_url
-
-  def GetPublicTimeline(self,
-                        since_id=None):
-    '''Fetch the sequnce of public twitter.Status message for all users.
-
-    @param since_id: Returns only public statuses with an ID greater than
-        (that is, more recent than) the specified ID. [optional]
-
-    @returns: An sequence of twitter.Status instances, one for each message
-    '''
-    parameters = {}
-
-    if since_id:
-      parameters['since_id'] = since_id
-
-    url  = '%s/statuses/public_timeline.json' % self.base_url
-    json = self._FetchUrl(url,  parameters=parameters)
-    data = json.loads(json)
-
-    self._CheckForTwitterError(data)
-
-    return [Status.NewFromJsonDict(x) for x in data]
-
-  def FilterPublicTimeline(self,
-                           term,
-                           since_id=None):
-    '''Filter the public twitter timeline by a given search term on
-    the local machine.
-
-    @param term: term to search by.
-    @param since_id: Returns only public statuses with an ID greater than
-        (that is, more recent than) the specified ID. [optional]
-
-    @returns: A sequence of twitter.Status instances, one for each message
-      containing the term
-    '''
-    statuses = self.GetPublicTimeline(since_id)
-    results  = []
-
-    for s in statuses:
-      if s.text.lower().find(term.lower()) != -1:
-        results.append(s)
-
-    return results
-
-  def GetSearch(self,
-                term,
-                geocode=None,
-                since_id=None,
-                per_page=15,
-                page=1,
-                lang="en",
-                show_user="true",
-                query_users=False):
-    '''Return twitter search results for a given term.
-
-    @param term: term to search by.
-    @param since_id: Returns only public statuses with an ID greater than
-        (that is, more recent than) the specified ID. [optional]
-    @param geocode: geolocation information in the form (latitude, longitude,
-        radius) [optional]
-    @param per_page: number of results to return.  Default is 15 [optional]
-    @param page: which page of search results to return
-    @param lang: language for results.  Default is English [optional]
-    @param show_user: prefixes screen name in status
-    @param query_users: If set to False, then all users only have screen_name
-        and profile_image_url available.
-        If set to True, all information of users are available,
-        but it uses lots of request quota, one per status.
-    @returns: A sequence of twitter.Status instances, one for each message
-        containing the term
-    '''
-    # Build request parameters
-    parameters = {}
-
-    if since_id:
-      parameters['since_id'] = since_id
-
-    if not term:
-      return []
-
-    parameters['q'] = urllib.quote_plus(term)
-    parameters['show_user'] = show_user
-    parameters['lang'] = lang
-    parameters['rpp'] = per_page
-    parameters['page'] = page
-
-    if geocode is not None:
-      parameters['geocode'] = ','.join(map(str, geocode))
-
-    # Make and send requests
-    url  = 'http://search.twitter.com/search.json'
-    json = self._FetchUrl(url, parameters=parameters)
-    data = json.loads(json)
-
-    self._CheckForTwitterError(data)
-
-    results = []
-
-    for x in data['results']:
-      temp = Status.NewFromJsonDict(x)
-
-      if query_users:
-        # Build user object with new request
-        temp.user = self.GetUser(urllib.quote(x['from_user']))
-      else:
-        temp.user = User(screen_name=x['from_user'], profile_image_url=x['profile_image_url'])
-
-      results.append(temp)
-
-    # Return built list of statuses
-    return results # [Status.NewFromJsonDict(x) for x in data['results']]
-
-  def GetFriendsTimeline(self,
-                         user=None,
-                         count=None,
-                         since=None,
-                         since_id=None):
-    '''Fetch the sequence of twitter.Status messages for a user's friends
-
-    The twitter.Api instance must be authenticated if the user is private.
-
-    @param user: Specifies the ID or screen name of the user for whom to return
-        the friends_timeline.  If unspecified, the username and password
-        must be set in the twitter.Api instance.  [Optional]
-    @param count: Specifies the number of statuses to retrieve. May not be
-        greater than 200. [Optional]
-    @param since: Narrows the returned results to just those statuses created
-        after the specified HTTP-formatted date. [Optional]
-    @param since_id: Returns only public statuses with an ID greater than (that
-        is, more recent than) the specified ID. [Optional]
-
-    @returns: A sequence of twitter.Status instances, one for each message
-    '''
-    if not user and not self._username:
-      raise TwitterError("User must be specified if API is not authenticated.")
-    if user:
-      url = '%s/statuses/friends_timeline/%s.json' % (self.base_url, user)
-    else:
-      url = '%s/statuses/friends_timeline.json' % self.base_url
-    parameters = {}
-    if count is not None:
-      try:
-        if int(count) > 200:
-          raise TwitterError("'count' may not be greater than 200")
-      except ValueError:
-        raise TwitterError("'count' must be an integer")
-      parameters['count'] = count
-    if since:
-      parameters['since'] = since
-    if since_id:
-      parameters['since_id'] = since_id
-    json = self._FetchUrl(url, parameters=parameters)
-    data = json.loads(json)
-    self._CheckForTwitterError(data)
-    return [Status.NewFromJsonDict(x) for x in data]
-
-  def GetUserTimeline(self,
-                      id=None,
-                      user_id=None,
-                      screen_name=None,
+            a Twitter "short name" or their user id.
+
+            >>> statuses = api.GetUserTimeline(user)
+            >>> print [s.text for s in statuses]
+
+        - To use authentication, instantiate the twitter.Api class with a
+            username and password:
+
+            >>> api = twitter.Api(username='twitter user',
+                                                  password='twitter pass')
+
+        - To fetch your friends (after being authenticated):
+
+            >>> users = api.GetFriends()
+            >>> print [u.name for u in users]
+
+        - To post a twitter status message (after being authenticated):
+
+            >>> status = api.PostUpdate('I love python-twitter!')
+            >>> print status.text
+            I love python-twitter!
+
+        - There are many other methods, including:
+
+            >>> api.PostUpdates(status)
+            >>> api.PostDirectMessage(user, text)
+            >>> api.GetUser(user)
+            >>> api.GetReplies()
+            >>> api.GetUserTimeline(user)
+            >>> api.GetStatus(id)
+            >>> api.DestroyStatus(id)
+            >>> api.GetFriendsTimeline(user)
+            >>> api.GetFriends(user)
+            >>> api.GetFollowers()
+            >>> api.GetFeatured()
+            >>> api.GetDirectMessages()
+            >>> api.PostDirectMessage(user, text)
+            >>> api.DestroyDirectMessage(id)
+            >>> api.DestroyFriendship(user)
+            >>> api.CreateFriendship(user)
+            >>> api.GetUserByEmail(email)
+            >>> api.VerifyCredentials()
+    '''
+
+    DEFAULT_CACHE_TIMEOUT = 60 # cache for 1 minute
+
+    _API_REALM = 'Twitter API'
+
+    def __init__(self,
+                 username=None,
+                 password=None,
+                 input_encoding=None,
+                 request_headers=None,
+                 cache=DEFAULT_CACHE,
+                 shortner=None,
+                 base_url=None,
+                 use_gzip_compression=False):
+        '''Instantiate a new twitter.Api object.
+
+        @param username: The username of the twitter account.  [optional]
+        @param password: The password for the twitter account. [optional]
+        @param input_encoding: The encoding used to encode input strings.
+            [optional]
+        @param request_header: A dictionary of additional HTTP request headers.
+            [optional]
+        @param cache: The cache instance to use. Defaults to DEFAULT_CACHE.
+            Use None to disable caching. [optional]
+        @param shortner: The shortner instance to use.  Defaults to None.
+            See shorten_url.py for an example shortner. [optional]
+        @param base_url: The base URL to use to contact the Twitter API.
+            Defaults to https://twitter.com. [optional]
+        @param use_gzip_compression: Set to True to tell enable gzip
+            compression for any call made to Twitter.
+            Defaults to False. [optional]
+        '''
+        self.SetCache(cache)
+        self._urllib = urllib2
+        self._cache_timeout = Api.DEFAULT_CACHE_TIMEOUT
+        self._InitializeRequestHeaders(request_headers)
+        self._InitializeUserAgent()
+        self._InitializeDefaultParameters()
+        self._input_encoding = input_encoding
+        self._use_gzip = use_gzip_compression
+        self.SetCredentials(username, password)
+        if base_url is None:
+            self.base_url = 'https://twitter.com'
+        else:
+            self.base_url = base_url
+
+    def GetPublicTimeline(self,
+                            since_id=None):
+        '''Fetch the sequnce of public twitter.Status message for all users.
+
+        @param since_id: Returns only public statuses with an ID greater than
+            (that is, more recent than) the specified ID. [optional]
+
+        @returns: An sequence of twitter.Status instances, one for each message
+        '''
+        parameters = {}
+
+        if since_id:
+            parameters['since_id'] = since_id
+
+        url = '%s/statuses/public_timeline.json' % self.base_url
+        json = self._FetchUrl(url, parameters=parameters)
+        data = json.loads(json)
+
+        self._CheckForTwitterError(data)
+
+        return [Status.NewFromJsonDict(x) for x in data]
+
+    def FilterPublicTimeline(self,
+                                term,
+                                since_id=None):
+        '''Filter the public twitter timeline by a given search term on
+        the local machine.
+
+        @param term: term to search by.
+        @param since_id: Returns only public statuses with an ID greater than
+            (that is, more recent than) the specified ID. [optional]
+
+        @returns: A sequence of twitter.Status instances, one for each message
+          containing the term
+        '''
+        statuses = self.GetPublicTimeline(since_id)
+        results = []
+
+        for s in statuses:
+            if s.text.lower().find(term.lower()) != -1:
+                results.append(s)
+
+        return results
+
+    def GetSearch(self,
+                    term,
+                    geocode=None,
+                    since_id=None,
+                    per_page=15,
+                    page=1,
+                    lang="en",
+                    show_user="true",
+                    query_users=False):
+        '''Return twitter search results for a given term.
+
+        @param term: term to search by.
+        @param since_id: Returns only public statuses with an ID greater than
+            (that is, more recent than) the specified ID. [optional]
+        @param geocode: geolocation information in the form (latitude,
+                        longitude, radius) [optional]
+        @param per_page: number of results to return.  Default is 15 [optional]
+        @param page: which page of search results to return
+        @param lang: language for results.  Default is English [optional]
+        @param show_user: prefixes screen name in status
+        @param query_users: If set to False, then all users only have
+            screen_name and profile_image_url available.
+            If set to True, all information of users are available,
+            but it uses lots of request quota, one per status.
+        @returns: A sequence of twitter.Status instances, one for each message
+            containing the term
+        '''
+        # Build request parameters
+        parameters = {}
+
+        if since_id:
+            parameters['since_id'] = since_id
+
+        if not term:
+            return []
+
+        parameters['q'] = urllib.quote_plus(term)
+        parameters['show_user'] = show_user
+        parameters['lang'] = lang
+        parameters['rpp'] = per_page
+        parameters['page'] = page
+
+        if geocode is not None:
+            parameters['geocode'] = ','.join(map(str, geocode))
+
+        # Make and send requests
+        url = 'http://search.twitter.com/search.json'
+        json = self._FetchUrl(url, parameters=parameters)
+        data = json.loads(json)
+
+        self._CheckForTwitterError(data)
+
+        results = []
+
+        for x in data['results']:
+            temp = Status.NewFromJsonDict(x)
+
+        if query_users:
+            # Build user object with new request
+            temp.user = self.GetUser(urllib.quote(x['from_user']))
+        else:
+            temp.user = User(screen_name=x['from_user'],
+                                profile_image_url=x['profile_image_url'])
+
+        results.append(temp)
+
+        # Return built list of statuses
+        return results # [Status.NewFromJsonDict(x) for x in data['results']]
+
+    def GetFriendsTimeline(self,
+                             user=None,
+                             count=None,
+                             since=None,
+                             since_id=None):
+        '''Fetch the sequence of twitter.Status messages for a user's friends
+
+        The twitter.Api instance must be authenticated if the user is private.
+
+        @param user: Specifies the ID or screen name of the user for whom to
+            return the friends_timeline.  If unspecified, the username and
+            password must be set in the twitter.Api instance.  [Optional]
+        @param count: Specifies the number of statuses to retrieve. May not be
+                      greater than 200. [Optional]
+        @param since: Narrows the returned results to just those statuses
+                   created after the specified HTTP-formatted date. [Optional]
+        @param since_id: Returns only public statuses with an ID greater than
+                      (that is, more recent than) the specified ID. [Optional]
+
+        @returns: A sequence of twitter.Status instances, one for each message
+        '''
+        if not user and not self._username:
+            raise TwitterError("User must be specified if API is not authent\
+                                                                     icated.")
+        if user:
+            url = '%s/statuses/friends_timeline/%s.json' % (self.base_url,
+                                                                         user)
+        else:
+            url = '%s/statuses/friends_timeline.json' % self.base_url
+        parameters = {}
+        if count is not None:
+            try:
+                if int(count) > 200:
+                    raise TwitterError("'count' may not be greater than 200")
+            except ValueError:
+                raise TwitterError("'count' must be an integer")
+            parameters['count'] = count
+        if since:
+            parameters['since'] = since
+        if since_id:
+            parameters['since_id'] = since_id
+        json = self._FetchUrl(url, parameters=parameters)
+        data = json.loads(json)
+        self._CheckForTwitterError(data)
+        return [Status.NewFromJsonDict(x) for x in data]
+
+    def GetUserTimeline(self,
+                          id=None,
+                          user_id=None,
+                          screen_name=None,
+                          since_id=None,
+                          max_id=None,
+                          count=None,
+                          page=None):
+        '''Fetch the sequence of public Status messages for a single user.
+
+        The twitter.Api instance must be authenticated if the user is private.
+
+        @param id: Specifies the ID or screen name of the user for whom to
+                   return the user_timeline. [optional]
+        @param user_id: Specfies the ID of the user for whom to return the
+            user_timeline. Helpful for disambiguating when a valid user ID
+            is also a valid screen name. [optional]
+        @param screen_name: Specfies the screen name of the user for whom to
+            return the user_timeline. Helpful for disambiguating when a valid
+            screen name is also a user ID. [optional]
+        @param since_id: Returns only public statuses with an ID greater than
+                     (that is, more recent than) the specified ID. [optional]
+        @param max_id: Returns only statuses with an ID less than (that is,
+                       older than) or equal to the specified ID. [optional]
+        @param count: Specifies the number of statuses to retrieve. May not be
+            greater than 200.  [optional]
+        @param page: Specifies the page of results to retrieve. Note: there are
+            pagination limits. [optional]
+
+        @returns: A sequence of Status instances, one for each message up to
+                  count
+        '''
+        parameters = {}
+
+        if id:
+            url = '%s/statuses/user_timeline/%s.json' % (self.base_url, id)
+        elif user_id:
+            url = '%s/statuses/user_timeline.json?user_id=%d' % (self.base_url,
+                                                                 user_id)
+        elif screen_name:
+            url = ('%s/statuses/user_timeline.json?screen_name=%s' % (
+                                                   self.base_url, screen_name))
+        elif not self._username:
+            raise TwitterError("User must be specified if API is not \
+                                                               authenticated.")
+        else:
+            url = '%s/statuses/user_timeline.json' % self.base_url
+
+        if since_id:
+            try:
+                parameters['since_id'] = long(since_id)
+            except:
+                raise TwitterError("since_id must be an integer")
+
+        if max_id:
+            try:
+                parameters['max_id'] = long(max_id)
+            except:
+                raise TwitterError("max_id must be an integer")
+
+        if count:
+            try:
+                parameters['count'] = int(count)
+            except:
+                raise TwitterError("count must be an integer")
+
+        if page:
+            try:
+                parameters['page'] = int(page)
+            except:
+                raise TwitterError("page must be an integer")
+
+        json = self._FetchUrl(url, parameters=parameters)
+        data = json.loads(json)
+        self._CheckForTwitterError(data)
+        return [Status.NewFromJsonDict(x) for x in data]
+
+    def GetStatus(self, id):
+        '''Returns a single status message.
+
+        The twitter.Api instance must be authenticated if the status message is
+        private.
+
+        @param id: The numerical ID of the status you're trying to retrieve.
+
+        @returns: A twitter.Status instance representing that status message
+        '''
+        try:
+            if id:
+                long(id)
+        except:
+            raise TwitterError("id must be an long integer")
+        url = '%s/statuses/show/%s.json' % (self.base_url, id)
+        json = self._FetchUrl(url)
+        data = json.loads(json)
+        self._CheckForTwitterError(data)
+        return Status.NewFromJsonDict(data)
+
+    def DestroyStatus(self, id):
+        '''Destroys the status specified by the required ID parameter.
+
+        The twitter.Api instance must be authenticated and thee
+        authenticating user must be the author of the specified status.
+
+        @param id: The numerical ID of the status you're trying to destroy.
+
+        @returns: A twitter.Status instance representing the destroyed status
+                  message
+        '''
+        try:
+            if id:
+                long(id)
+        except:
+            raise TwitterError("id must be an integer")
+        url = '%s/statuses/destroy/%s.json' % (self.base_url, id)
+        json = self._FetchUrl(url, post_data={})
+        data = json.loads(json)
+        self._CheckForTwitterError(data)
+        return Status.NewFromJsonDict(data)
+
+    def PostUpdate(self, status, in_reply_to_status_id=None):
+        '''Post a twitter status message from the authenticated user.
+
+        The twitter.Api instance must be authenticated.
+
+        @param status: The message text to be posted.  Must be less than or
+                       equal to 140 characters.
+        @param in_reply_to_status_id: The ID of an existing status that the
+            status to be posted is in reply to.  This implicitly sets the
+            in_reply_to_user_id attribute of the resulting status to the user
+            ID of the message being replied to.  Invalid/missing status IDs
+            will be ignored. [Optional]
+        @returns: A twitter.Status instance representing the message posted.
+        '''
+        if not self._username:
+            raise TwitterError("The twitter.Api instance must be \
+                                                            authenticated.")
+
+        url = '%s/statuses/update.json' % self.base_url
+
+        if len(status) > CHARACTER_LIMIT:
+            raise TwitterError("Text must be less than or equal to %d \
+                                                                 characters. "
+                               "Consider using PostUpdates." % CHARACTER_LIMIT)
+
+        data = {'status': status}
+        if in_reply_to_status_id:
+            data['in_reply_to_status_id'] = in_reply_to_status_id
+            json = self._FetchUrl(url, post_data=data)
+            data = json.loads(json)
+            self._CheckForTwitterError(data)
+        return Status.NewFromJsonDict(data)
+
+    def PostUpdates(self, status, continuation=None, **kwargs):
+        '''Post one or more twitter status messages from the authenticated user
+
+        Unlike api.PostUpdate, this method will post multiple status updates
+        if the message is longer than 140 characters.
+
+        The twitter.Api instance must be authenticated.
+
+        @param status: The message text to be posted.  May be longer than 140
+            characters.
+        @param continuation: The character string, if any, to be appended to
+            all but the last message.  Note that Twitter strips trailing '...'
+            strings from messages.  Consider using the unicode \u2026 character
+            (horizontal ellipsis) instead. [Defaults to None]
+        @param **kwargs: See api.PostUpdate for a list of accepted parameters.
+        @returns: A of list twitter.Status instance representing the messages
+                  posted.
+        '''
+        results = list()
+        if continuation is None:
+            continuation = ''
+        line_length = CHARACTER_LIMIT - len(continuation)
+        lines = textwrap.wrap(status, line_length)
+        for line in lines[0:-1]:
+            results.append(self.PostUpdate(line + continuation, **kwargs))
+        results.append(self.PostUpdate(lines[-1], **kwargs))
+        return results
+
+    def GetReplies(self, since=None, since_id=None, page=None):
+        '''Get a sequence of status messages representing the 20 most recent
+        replies (status updates prefixed with @username) to the authenticating
+        user.
+
+        @param page:
+        @param since: Narrows the returned results to just those statuses
+                   created after the specified HTTP-formatted date. [optional]
+        @param since_id: Returns only public statuses with an ID greater than
+                      (that is, more recent than) the specified ID. [Optional]
+
+        @returns: A sequence of twitter.Status instances, one for each reply to
+                  the user.
+        '''
+        url = '%s/statuses/replies.json' % self.base_url
+        if not self._username:
+            raise TwitterError("The twitter.Api instance must be \
+                                                              authenticated.")
+        parameters = {}
+        if since:
+            parameters['since'] = since
+        if since_id:
+            parameters['since_id'] = since_id
+        if page:
+            parameters['page'] = page
+        json = self._FetchUrl(url, parameters=parameters)
+        data = json.loads(json)
+        self._CheckForTwitterError(data)
+        return [Status.NewFromJsonDict(x) for x in data]
+
+    def GetFriends(self, user=None, page=None):
+        '''Fetch the sequence of twitter.User instances, one for each friend.
+
+        The twitter.Api instance must be authenticated.
+
+        @param user: the username or id of the user whose friends you are
+            fetching. If not specified, defaults to the authenticated user.
+            [optional]
+        @returns: A sequence of twitter.User instances, one for each friend
+        '''
+        if not user and not self._username:
+            raise TwitterError("twitter.Api instance must be authenticated")
+        if user:
+            url = '%s/statuses/friends/%s.json' % (self.base_url, user)
+        else:
+            url = '%s/statuses/friends.json' % self.base_url
+        parameters = {}
+        if page:
+            parameters['page'] = page
+        json = self._FetchUrl(url, parameters=parameters)
+        data = json.loads(json)
+        self._CheckForTwitterError(data)
+        return [User.NewFromJsonDict(x) for x in data]
+
+    def GetFriendIDs(self, user=None, page=None):
+        '''Returns a list of twitter user id's for every person
+        the specified user is following.
+
+        @param user: The id or screen_name of the user to retrieve the id list
+          for [optional]
+        @param page: Specifies the page number of the results beginning at 1.
+            A single page contains 5000 ids. This is recommended for users
+            with large id lists. If not provided all id's are returned.
+            (Please note that the result set isn't guaranteed to be 5000
+            every time as suspended users will be filtered.) [optional]
+
+        @returns: A list of integers, one for each user id.
+        '''
+        if not user and not self._username:
+            raise TwitterError("twitter.Api instance must be authenticated")
+        if user:
+            url = '%s/friends/ids/%s.json' % (self.base_url, user)
+        else:
+            url = '%s/friends/ids.json' % self.base_url
+        parameters = {}
+        if page:
+            parameters['page'] = page
+        json = self._FetchUrl(url, parameters=parameters)
+        data = json.loads(json)
+        self._CheckForTwitterError(data)
+        return data
+
+    def GetFollowers(self, page=None):
+        '''Fetch the sequence of twitter.User instances, one for each follower
+
+        The twitter.Api instance must be authenticated.
+
+        @returns: A sequence of twitter.User instances, one for each follower
+        '''
+        if not self._username:
+            raise TwitterError("twitter.Api instance must be authenticated")
+        url = '%s/statuses/followers.json' % self.base_url
+        parameters = {}
+        if page:
+            parameters['page'] = page
+        json = self._FetchUrl(url, parameters=parameters)
+        data = json.loads(json)
+        self._CheckForTwitterError(data)
+        return [User.NewFromJsonDict(x) for x in data]
+
+    def GetFeatured(self):
+        '''Fetch the sequence of twitter.User instances featured on twitter.com
+
+        The twitter.Api instance must be authenticated.
+
+        @returns: A sequence of twitter.User instances
+        '''
+        url = '%s/statuses/featured.json' % self.base_url
+        json = self._FetchUrl(url)
+        data = json.loads(json)
+        self._CheckForTwitterError(data)
+        return [User.NewFromJsonDict(x) for x in data]
+
+    def GetUser(self, user):
+        '''Returns a single user.
+
+        The twitter.Api instance must be authenticated.
+
+        @param user: The username or id of the user to retrieve.
+
+        @returns: A twitter.User instance representing that user
+        '''
+        url = '%s/users/show/%s.json' % (self.base_url, user)
+        json = self._FetchUrl(url)
+        data = json.loads(json)
+        self._CheckForTwitterError(data)
+        return User.NewFromJsonDict(data)
+
+    def GetDirectMessages(self, since=None, since_id=None, page=None):
+        '''Returns a list of the direct messages sent to the authenticating
+        user.
+
+        The twitter.Api instance must be authenticated.
+
+        @param since: Narrows the returned results to just those statuses
+                    created after the specified HTTP-formatted date. [optional]
+        @param since_id: Returns only public statuses with an ID greater than
+                       (that is, more recent than) the specified ID. [Optional]
+
+        @returns: A sequence of twitter.DirectMessage instances
+        '''
+        url = '%s/direct_messages.json' % self.base_url
+        if not self._username:
+            raise TwitterError("The twitter.Api instance must be \
+                                                               authenticated.")
+        parameters = {}
+        if since:
+            parameters['since'] = since
+        if since_id:
+            parameters['since_id'] = since_id
+        if page:
+            parameters['page'] = page
+        json = self._FetchUrl(url, parameters=parameters)
+        data = json.loads(json)
+        self._CheckForTwitterError(data)
+        return [DirectMessage.NewFromJsonDict(x) for x in data]
+
+    def PostDirectMessage(self, user, text):
+        '''Post a twitter direct message from the authenticated user
+
+        The twitter.Api instance must be authenticated.
+
+        @param user: The ID or screen name of the recipient user.
+        @param text: The message text to be posted.  Must be less than 140
+                     characters.
+
+        @returns: A twitter.DirectMessage instance representing the message
+                  posted
+        '''
+        if not self._username:
+            raise TwitterError("The twitter.Api instance must be \
+                                                           authenticated.")
+        url = '%s/direct_messages/new.json' % self.base_url
+        data = {'text': text, 'user': user}
+        json = self._FetchUrl(url, post_data=data)
+        data = json.loads(json)
+        self._CheckForTwitterError(data)
+        return DirectMessage.NewFromJsonDict(data)
+
+    def DestroyDirectMessage(self, id):
+        '''Destroys the direct message specified in the required ID parameter.
+
+        The twitter.Api instance must be authenticated, and the
+        authenticating user must be the recipient of the specified direct
+        message.
+
+        @param id: The id of the direct message to be destroyed
+
+        @returns: A twitter.DirectMessage instance representing the message
+                  destroyed
+        '''
+        url = '%s/direct_messages/destroy/%s.json' % (self.base_url, id)
+        json = self._FetchUrl(url, post_data={})
+        data = json.loads(json)
+        self._CheckForTwitterError(data)
+        return DirectMessage.NewFromJsonDict(data)
+
+    def CreateFriendship(self, user):
+        '''Befriends the user specified in the user parameter as the
+        authenticating user.
+
+        The twitter.Api instance must be authenticated.
+
+        @param user: The ID or screen name of the user to befriend.
+        @returns: A twitter.User instance representing the befriended user.
+        '''
+        url = '%s/friendships/create/%s.json' % (self.base_url, user)
+        json = self._FetchUrl(url, post_data={})
+        data = json.loads(json)
+        self._CheckForTwitterError(data)
+        return User.NewFromJsonDict(data)
+
+    def DestroyFriendship(self, user):
+        '''Discontinues friendship with the user specified in the user
+        parameter.
+
+        The twitter.Api instance must be authenticated.
+
+        @param user: The ID or screen name of the user  with whom to
+                     discontinue friendship.
+        @returns: A twitter.User instance representing the discontinued friend.
+        '''
+        url = '%s/friendships/destroy/%s.json' % (self.base_url, user)
+        json = self._FetchUrl(url, post_data={})
+        data = json.loads(json)
+        self._CheckForTwitterError(data)
+        return User.NewFromJsonDict(data)
+
+    def CreateFavorite(self, status):
+        '''Favorites the status specified in the status parameter as the
+        authenticating user.
+        Returns the favorite status when successful.
+
+        The twitter.Api instance must be authenticated.
+
+        @param status: The twitter.Status instance to mark as a favorite.
+        @returns: A twitter.Status instance representing the newly-marked
+                  favorite.
+        '''
+        url = '%s/favorites/create/%s.json' % (self.base_url, status.id)
+        json = self._FetchUrl(url, post_data={})
+        data = json.loads(json)
+        self._CheckForTwitterError(data)
+        return Status.NewFromJsonDict(data)
+
+    def DestroyFavorite(self, status):
+        '''Un-favorites the status specified in the ID parameter as the
+        authenticating user. Returns the un-favorited status in the requested
+        format when successful.
+
+        The twitter.Api instance must be authenticated.
+
+        @param status: The twitter.Status to unmark as a favorite.
+        @returns: A twitter.Status instance representing the newly-unmarked
+                  favorite.
+        '''
+        url = '%s/favorites/destroy/%s.json' % (self.base_url, status.id)
+        json = self._FetchUrl(url, post_data={})
+        data = json.loads(json)
+        self._CheckForTwitterError(data)
+        return Status.NewFromJsonDict(data)
+
+    def GetFavorites(self,
+                       user=None,
+                       page=None):
+        '''Return a list of Status objects representing favorited tweets.
+        By default, returns the (up to) 20 most recent tweets for the
+        authenticated user.
+
+        @param user: The username or id of the user whose favorites you are
+            fetching. If not specified, defaults to the authenticated user.
+            [optional]
+
+        @param page: Retrieves the 20 next most recent favorite statuses.
+            [optional]
+        '''
+        parameters = {}
+
+        if page:
+            parameters['page'] = page
+
+        if user:
+            url = '%s/favorites/%s.json' % (self.base_url, user)
+        elif not user and not self._username:
+                raise TwitterError("User must be specified if API is not \
+                                                              authenticated.")
+        else:
+                url = '%s/favorites.json' % self.base_url
+
+        json = self._FetchUrl(url, parameters=parameters)
+        data = json.loads(json)
+
+        self._CheckForTwitterError(data)
+
+        return [Status.NewFromJsonDict(x) for x in data]
+
+    def GetMentions(self,
                       since_id=None,
                       max_id=None,
-                      count=None,
                       page=None):
-    '''Fetch the sequence of public Status messages for a single user.
-
-    The twitter.Api instance must be authenticated if the user is private.
-
-    @param id: Specifies the ID or screen name of the user for whom to return
-        the user_timeline. [optional]
-    @param user_id: Specfies the ID of the user for whom to return the
-        user_timeline. Helpful for disambiguating when a valid user ID
-        is also a valid screen name. [optional]
-    @param screen_name: Specfies the screen name of the user for whom to return
-        the user_timeline. Helpful for disambiguating when a valid screen
-        name is also a user ID. [optional]
-    @param since_id: Returns only public statuses with an ID greater than (that
-        is, more recent than) the specified ID. [optional]
-    @param max_id: Returns only statuses with an ID less than (that is, older
-        than) or equal to the specified ID. [optional]
-    @param count: Specifies the number of statuses to retrieve. May not be
-        greater than 200.  [optional]
-    @param page: Specifies the page of results to retrieve. Note: there are
-         pagination limits. [optional]
-
-    @returns: A sequence of Status instances, one for each message up to count
-    '''
-    parameters = {}
-
-    if id:
-      url = '%s/statuses/user_timeline/%s.json' % (self.base_url, id)
-    elif user_id:
-      url = '%s/statuses/user_timeline.json?user_id=%d' % (self.base_url, user_id)
-    elif screen_name:
-      url = ('%s/statuses/user_timeline.json?screen_name=%s' % (self.base_url,
-             screen_name))
-    elif not self._username:
-      raise TwitterError("User must be specified if API is not authenticated.")
-    else:
-      url = '%s/statuses/user_timeline.json' % self.base_url
-
-    if since_id:
-      try:
-        parameters['since_id'] = long(since_id)
-      except:
-        raise TwitterError("since_id must be an integer")
-
-    if max_id:
-      try:
-        parameters['max_id'] = long(max_id)
-      except:
-        raise TwitterError("max_id must be an integer")
-
-    if count:
-      try:
-        parameters['count'] = int(count)
-      except:
-        raise TwitterError("count must be an integer")
-
-    if page:
-      try:
-        parameters['page'] = int(page)
-      except:
-        raise TwitterError("page must be an integer")
-
-    json = self._FetchUrl(url, parameters=parameters)
-    data = json.loads(json)
-    self._CheckForTwitterError(data)
-    return [Status.NewFromJsonDict(x) for x in data]
-
-  def GetStatus(self, id):
-    '''Returns a single status message.
-
-    The twitter.Api instance must be authenticated if the status message is private.
-
-    @param id: The numerical ID of the status you're trying to retrieve.
-
-    @returns: A twitter.Status instance representing that status message
-    '''
-    try:
-      if id:
-        long(id)
-    except:
-      raise TwitterError("id must be an long integer")
-    url = '%s/statuses/show/%s.json' % (self.base_url, id)
-    json = self._FetchUrl(url)
-    data = json.loads(json)
-    self._CheckForTwitterError(data)
-    return Status.NewFromJsonDict(data)
-
-  def DestroyStatus(self, id):
-    '''Destroys the status specified by the required ID parameter.
-
-    The twitter.Api instance must be authenticated and thee
-    authenticating user must be the author of the specified status.
-
-    @param id: The numerical ID of the status you're trying to destroy.
-
-    @returns: A twitter.Status instance representing the destroyed status message
-    '''
-    try:
-      if id:
-        long(id)
-    except:
-      raise TwitterError("id must be an integer")
-    url = '%s/statuses/destroy/%s.json' % (self.base_url, id)
-    json = self._FetchUrl(url, post_data={})
-    data = json.loads(json)
-    self._CheckForTwitterError(data)
-    return Status.NewFromJsonDict(data)
-
-  def PostUpdate(self, status, in_reply_to_status_id=None):
-    '''Post a twitter status message from the authenticated user.
-
-    The twitter.Api instance must be authenticated.
-
-    @param status: The message text to be posted.  Must be less than or equal
-        to 140 characters.
-    @param in_reply_to_status_id: The ID of an existing status that the status
-        to be posted is in reply to.  This implicitly sets the 
-        in_reply_to_user_id attribute of the resulting status to the user ID of
-        the message being replied to.  Invalid/missing status IDs will be
-        ignored. [Optional]
-    @returns: A twitter.Status instance representing the message posted.
-    '''
-    if not self._username:
-      raise TwitterError("The twitter.Api instance must be authenticated.")
-
-    url = '%s/statuses/update.json' % self.base_url
-
-    if len(status) > CHARACTER_LIMIT:
-      raise TwitterError("Text must be less than or equal to %d characters. "
-                         "Consider using PostUpdates." % CHARACTER_LIMIT)
-
-    data = {'status': status}
-    if in_reply_to_status_id:
-      data['in_reply_to_status_id'] = in_reply_to_status_id
-    json = self._FetchUrl(url, post_data=data)
-    data = json.loads(json)
-    self._CheckForTwitterError(data)
-    return Status.NewFromJsonDict(data)
-
-  def PostUpdates(self, status, continuation=None, **kwargs):
-    '''Post one or more twitter status messages from the authenticated user.
-
-    Unlike api.PostUpdate, this method will post multiple status updates
-    if the message is longer than 140 characters.
-
-    The twitter.Api instance must be authenticated.
-
-    @param status: The message text to be posted.  May be longer than 140 
-        characters.
-    @param continuation: The character string, if any, to be appended to all
-        but the last message.  Note that Twitter strips trailing '...' strings
-        from messages.  Consider using the unicode \u2026 character
-        (horizontal ellipsis) instead. [Defaults to None]
-    @param **kwargs: See api.PostUpdate for a list of accepted parameters.
-    @returns: A of list twitter.Status instance representing the messages posted.
-    '''
-    results = list()
-    if continuation is None:
-      continuation = ''
-    line_length = CHARACTER_LIMIT - len(continuation)
-    lines = textwrap.wrap(status, line_length)
-    for line in lines[0:-1]:
-      results.append(self.PostUpdate(line + continuation, **kwargs))
-    results.append(self.PostUpdate(lines[-1], **kwargs))
-    return results
-
-  def GetReplies(self, since=None, since_id=None, page=None): 
-    '''Get a sequence of status messages representing the 20 most recent
-    replies (status updates prefixed with @username) to the authenticating
-    user.
-
-    @param page: 
-    @param since: Narrows the returned results to just those statuses created
-        after the specified HTTP-formatted date. [optional]
-    @param since_id: Returns only public statuses with an ID greater than (that
-        is, more recent than) the specified ID. [Optional]
-
-    @returns: A sequence of twitter.Status instances, one for each reply to the
-        user.
-    '''
-    url = '%s/statuses/replies.json' % self.base_url
-    if not self._username:
-      raise TwitterError("The twitter.Api instance must be authenticated.")
-    parameters = {}
-    if since:
-      parameters['since'] = since
-    if since_id:
-      parameters['since_id'] = since_id
-    if page:
-      parameters['page'] = page
-    json = self._FetchUrl(url, parameters=parameters)
-    data = json.loads(json)
-    self._CheckForTwitterError(data)
-    return [Status.NewFromJsonDict(x) for x in data]
-
-  def GetFriends(self, user=None, page=None):
-    '''Fetch the sequence of twitter.User instances, one for each friend.
-
-    The twitter.Api instance must be authenticated.
-
-    @param user: the username or id of the user whose friends you are fetching.
-        If not specified, defaults to the authenticated user. [optional]
-
-    @returns: A sequence of twitter.User instances, one for each friend
-    '''
-    if not user and not self._username:
-      raise TwitterError("twitter.Api instance must be authenticated")
-    if user:
-      url = '%s/statuses/friends/%s.json' % (self.base_url, user)
-    else:
-      url = '%s/statuses/friends.json' % self.base_url
-    parameters = {}
-    if page:
-      parameters['page'] = page
-    json = self._FetchUrl(url, parameters=parameters)
-    data = json.loads(json)
-    self._CheckForTwitterError(data)
-    return [User.NewFromJsonDict(x) for x in data]
-
-  def GetFriendIDs(self, user=None, page=None):
-      '''Returns a list of twitter user id's for every person
-      the specified user is following.
-
-      @param user: The id or screen_name of the user to retrieve the id list
-        for [optional]
-      @param page: Specifies the page number of the results beginning at 1.
-          A single page contains 5000 ids. This is recommended for users
-          with large id lists. If not provided all id's are returned. 
-          (Please note that the result set isn't guaranteed to be 5000 
-          every time as suspended users will be filtered.) [optional]
-
-      @returns: A list of integers, one for each user id.
-      '''
-      if not user and not self._username:
-          raise TwitterError("twitter.Api instance must be authenticated")
-      if user:
-          url = '%s/friends/ids/%s.json' % (self.base_url, user)
-      else:
-          url = '%s/friends/ids.json' % self.base_url
-      parameters = {}
-      if page:
-          parameters['page'] = page
-      json = self._FetchUrl(url, parameters=parameters)
-      data = json.loads(json)
-      self._CheckForTwitterError(data)
-      return data
-
-  def GetFollowers(self, page=None):
-    '''Fetch the sequence of twitter.User instances, one for each follower
-
-    The twitter.Api instance must be authenticated.
-
-    @returns: A sequence of twitter.User instances, one for each follower
-    '''
-    if not self._username:
-      raise TwitterError("twitter.Api instance must be authenticated")
-    url = '%s/statuses/followers.json' % self.base_url
-    parameters = {}
-    if page:
-      parameters['page'] = page
-    json = self._FetchUrl(url, parameters=parameters)
-    data = json.loads(json)
-    self._CheckForTwitterError(data)
-    return [User.NewFromJsonDict(x) for x in data]
-
-  def GetFeatured(self):
-    '''Fetch the sequence of twitter.User instances featured on twitter.com
-
-    The twitter.Api instance must be authenticated.
-
-    @returns: A sequence of twitter.User instances
-    '''
-    url = '%s/statuses/featured.json' % self.base_url
-    json = self._FetchUrl(url)
-    data = json.loads(json)
-    self._CheckForTwitterError(data)
-    return [User.NewFromJsonDict(x) for x in data]
-
-  def GetUser(self, user):
-    '''Returns a single user.
-
-    The twitter.Api instance must be authenticated.
-
-    @param user: The username or id of the user to retrieve.
-
-    @returns: A twitter.User instance representing that user
-    '''
-    url = '%s/users/show/%s.json' % (self.base_url, user)
-    json = self._FetchUrl(url)
-    data = json.loads(json)
-    self._CheckForTwitterError(data)
-    return User.NewFromJsonDict(data)
-
-  def GetDirectMessages(self, since=None, since_id=None, page=None):
-    '''Returns a list of the direct messages sent to the authenticating user.
-
-    The twitter.Api instance must be authenticated.
-
-    @param since: Narrows the returned results to just those statuses created
-        after the specified HTTP-formatted date. [optional]
-    @param since_id: Returns only public statuses with an ID greater than (that
-        is, more recent than) the specified ID. [Optional]
-
-    @returns: A sequence of twitter.DirectMessage instances
-    '''
-    url = '%s/direct_messages.json' % self.base_url
-    if not self._username:
-      raise TwitterError("The twitter.Api instance must be authenticated.")
-    parameters = {}
-    if since:
-      parameters['since'] = since
-    if since_id:
-      parameters['since_id'] = since_id
-    if page:
-      parameters['page'] = page 
-    json = self._FetchUrl(url, parameters=parameters)
-    data = json.loads(json)
-    self._CheckForTwitterError(data)
-    return [DirectMessage.NewFromJsonDict(x) for x in data]
-
-  def PostDirectMessage(self, user, text):
-    '''Post a twitter direct message from the authenticated user
-
-    The twitter.Api instance must be authenticated.
-
-    @param user: The ID or screen name of the recipient user.
-    @param text: The message text to be posted.  Must be less than 140 characters.
-
-    @returns: A twitter.DirectMessage instance representing the message posted
-    '''
-    if not self._username:
-      raise TwitterError("The twitter.Api instance must be authenticated.")
-    url = '%s/direct_messages/new.json' % self.base_url
-    data = {'text': text, 'user': user}
-    json = self._FetchUrl(url, post_data=data)
-    data = json.loads(json)
-    self._CheckForTwitterError(data)
-    return DirectMessage.NewFromJsonDict(data)
-
-  def DestroyDirectMessage(self, id):
-    '''Destroys the direct message specified in the required ID parameter.
-
-    The twitter.Api instance must be authenticated, and the
-    authenticating user must be the recipient of the specified direct
-    message.
-
-    @param id: The id of the direct message to be destroyed
-
-    @returns: A twitter.DirectMessage instance representing the message destroyed
-    '''
-    url = '%s/direct_messages/destroy/%s.json' % (self.base_url, id)
-    json = self._FetchUrl(url, post_data={})
-    data = json.loads(json)
-    self._CheckForTwitterError(data)
-    return DirectMessage.NewFromJsonDict(data)
-
-  def CreateFriendship(self, user):
-    '''Befriends the user specified in the user parameter as the authenticating user.
-
-    The twitter.Api instance must be authenticated.
-
-    @param user: The ID or screen name of the user to befriend.
-    @returns: A twitter.User instance representing the befriended user.
-    '''
-    url = '%s/friendships/create/%s.json' % (self.base_url, user)
-    json = self._FetchUrl(url, post_data={})
-    data = json.loads(json)
-    self._CheckForTwitterError(data)
-    return User.NewFromJsonDict(data)
-
-  def DestroyFriendship(self, user):
-    '''Discontinues friendship with the user specified in the user parameter.
-
-    The twitter.Api instance must be authenticated.
-
-    @param user: The ID or screen name of the user  with whom to discontinue
-        friendship.
-    @returns: A twitter.User instance representing the discontinued friend.
-    '''
-    url = '%s/friendships/destroy/%s.json' % (self.base_url, user)
-    json = self._FetchUrl(url, post_data={})
-    data = json.loads(json)
-    self._CheckForTwitterError(data)
-    return User.NewFromJsonDict(data)
-
-  def CreateFavorite(self, status):
-    '''Favorites the status specified in the status parameter as the
-    authenticating user.
-    Returns the favorite status when successful.
-
-    The twitter.Api instance must be authenticated.
-
-    @param status: The twitter.Status instance to mark as a favorite.
-    @returns: A twitter.Status instance representing the newly-marked favorite.
-    '''
-    url = '%s/favorites/create/%s.json' % (self.base_url, status.id)
-    json = self._FetchUrl(url, post_data={})
-    data = json.loads(json)
-    self._CheckForTwitterError(data)
-    return Status.NewFromJsonDict(data)
-
-  def DestroyFavorite(self, status):
-    '''Un-favorites the status specified in the ID parameter as the authenticating user.
-    Returns the un-favorited status in the requested format when successful.
-
-    The twitter.Api instance must be authenticated.
-
-    @param status: The twitter.Status to unmark as a favorite.
-    @returns: A twitter.Status instance representing the newly-unmarked favorite.
-    '''
-    url = '%s/favorites/destroy/%s.json' % (self.base_url, status.id)
-    json = self._FetchUrl(url, post_data={})
-    data = json.loads(json)
-    self._CheckForTwitterError(data)
-    return Status.NewFromJsonDict(data)
-
-  def GetFavorites(self,
-                   user=None,
-                   page=None):
-    '''Return a list of Status objects representing favorited tweets.
-    By default, returns the (up to) 20 most recent tweets for the
-    authenticated user.
-    
-    @param user: The username or id of the user whose favorites you are
-        fetching. If not specified, defaults to the authenticated user.
-        [optional]
-    
-    @param page: Retrieves the 20 next most recent favorite statuses.
-        [optional]
-    '''
-    parameters = {}
-
-    if page:
-      parameters['page'] = page
-
-    if user:
-      url = '%s/favorites/%s.json' % (self.base_url, user)
-    elif not user and not self._username:
-      raise TwitterError("User must be specified if API is not authenticated.")
-    else:
-      url = '%s/favorites.json' % self.base_url
-
-    json = self._FetchUrl(url, parameters=parameters)
-    data = json.loads(json)
-
-    self._CheckForTwitterError(data)
-
-    return [Status.NewFromJsonDict(x) for x in data]
-
-  def GetMentions(self,
-                  since_id=None,
-                  max_id=None,
-                  page=None):
-    '''Returns the 20 most recent mentions (status containing @username)
-    for the authenticating user.
-    
-    @param since_id: Returns only public statuses with an ID greater than
-        (that is, more recent than) the specified ID. [optional]
-    
-    @param max_id: Returns only statuses with an ID less than
-        (that is, older than) the specified ID.  [optional]
-    
-    @param page: Retrieves the 20 next most recent replies. [optional]
-    
-    @returns: A sequence of twitter.Status instances, one for each mention of 
-        the user. see:
-        http://apiwiki.twitter.com/REST-API-Documentation#statuses/mentions
-    '''
-
-    url = '%s/statuses/mentions.json' % self.base_url
-
-    if not self._username:
-      raise TwitterError("The twitter.Api instance must be authenticated.")
-
-    parameters = {}
-
-    if since_id:
-      parameters['since_id'] = since_id
-    if max_id:
-      parameters['max_id'] = max_id
-    if page:
-      parameters['page'] = page
-
-    json = self._FetchUrl(url, parameters=parameters)
-    data = json.loads(json)
-
-    self._CheckForTwitterError(data)
-
-    return [Status.NewFromJsonDict(x) for x in data]
-
-  def GetUserByEmail(self, email):
-    '''Returns a single user by email address.
-
-    @param email: The email of the user to retrieve.
-    @returns: A twitter.User instance representing that user
-    '''
-    url = '%s/users/show.json?email=%s' % (self.base_url, email)
-    json = self._FetchUrl(url)
-    data = json.loads(json)
-    self._CheckForTwitterError(data)
-    return User.NewFromJsonDict(data)
-
-  def VerifyCredentials(self):
-    '''Returns a twitter.User instance if the authenticating user is valid.
-
-    @returns: A twitter.User instance representing that user if the
-      credentials are valid, None otherwise.
-    '''
-    if not self._username:
-      raise TwitterError("Api instance must first be given user credentials.")
-    url = '%s/account/verify_credentials.json' % self.base_url
-    try:
-      json = self._FetchUrl(url, no_cache=True)
-    except urllib2.HTTPError, http_error:
-      if http_error.code == httplib.UNAUTHORIZED:
-        return None
-      else:
-        raise http_error
-    data = json.loads(json)
-    self._CheckForTwitterError(data)
-    return User.NewFromJsonDict(data)
-
-  def SetCredentials(self, username, password):
-    '''Set the username and password for this instance
-
-    @param username: The twitter username.
-    @param password: The twitter password.
-    '''
-    self._username = username
-    self._password = password
-
-  def ClearCredentials(self):
-    '''Clear the username and password for this instance
-    '''
-    self._username = None
-    self._password = None
-
-  def SetCache(self, cache):
-    '''Override the default cache.  Set to None to prevent caching.
-
-    @param cache: an instance that supports the same API as the twitter._FileCache
-    '''
-    if cache == DEFAULT_CACHE:
-      self._cache = _FileCache()
-    else:
-      self._cache = cache
-
-  def SetUrllib(self, urllib):
-    '''Override the default urllib implementation.
-
-    @param urllib: an instance that supports the same API as the urllib2 module
-    '''
-    self._urllib = urllib
-
-  def SetCacheTimeout(self, cache_timeout):
-    '''Override the default cache timeout.
-
-    @param cache_timeout: time, in seconds, that responses should be reused.
-    '''
-    self._cache_timeout = cache_timeout
-
-  def SetUserAgent(self, user_agent):
-    '''Override the default user agent
-
-    @param user_agent: a string that should be send to the server as the User-agent
-    '''
-    self._request_headers['User-Agent'] = user_agent
-
-  def SetXTwitterHeaders(self, client, url, version):
-    '''Set the X-Twitter HTTP headers that will be sent to the server.
-
-    @param client: The client name as a string.  Will be sent to the server as
-         the 'X-Twitter-Client' header.
-    @param url: The URL of the meta.xml as a string.  Will be sent to the server
-         as the 'X-Twitter-Client-URL' header.
-    @param version: The client version as a string.  Will be sent to the server
-         as the 'X-Twitter-Client-Version' header.
-    '''
-    self._request_headers['X-Twitter-Client'] = client
-    self._request_headers['X-Twitter-Client-URL'] = url
-    self._request_headers['X-Twitter-Client-Version'] = version
-
-  def SetSource(self, source):
-    '''Suggest the "from source" value to be displayed on the Twitter web site.
-
-    The value of the 'source' parameter must be first recognized by
-    the Twitter server.  New source values are authorized on a case by
-    case basis by the Twitter development team.
-
-    @param source: The source name as a string.  Will be sent to the server as
-        the 'source' parameter.
-    '''
-    self._default_params['source'] = source
-
-  def GetRateLimitStatus(self):
-    '''Fetch the rate limit status for the currently authorized user.
-    
-    @returns: A dictionary containing the time the limit will reset 
-        (reset_time), the number of remaining hits allowed before the reset
-        (remaining_hits), the number of hits allowed in a 60-minute period 
-        (hourly_limit), and the time of the reset in seconds since The Epoch
-        (reset_time_in_seconds).
-    '''
-    url  = '%s/account/rate_limit_status.json' % self.base_url
-    json = self._FetchUrl(url, no_cache=True)
-    data = json.loads(json)
-
-    self._CheckForTwitterError(data)
-
-    return data
-
-  def MaximumHitFrequency(self):
-    '''Determines the minimum number of seconds that a program must wait before
-    hitting the server again without exceeding the rate_limit imposed for the
-    currently authenticated user.
-    
-    @returns: The minimum second interval that a program must use so as to not
-        exceed the rate_limit imposed for the user.
-    '''
-    rate_status = self.GetRateLimitStatus()
-    reset_time  = rate_status.get('reset_time', None)
-    limit       = rate_status.get('remaining_hits', None)
-
-    if reset_time and limit:
-      # put the reset time into a datetime object
-      reset = datetime.datetime(*rfc822.parsedate(reset_time)[:7])
-
-      # find the difference in time between now and the reset time + 1 hour
-      delta = reset + datetime.timedelta(hours=1) - datetime.datetime.utcnow()
-
-      # determine the minimum number of seconds allowed as a regular interval
-      max_frequency = int(delta.seconds / limit)
-
-      # return the number of seconds
-      return max_frequency
-
-    return 0
-
-  def _BuildUrl(self, url, path_elements=None, extra_params=None):
-    # Break url into consituent parts
-    (scheme, netloc, path, params, query, fragment) = urlparse.urlparse(url)
-
-    # Add any additional path elements to the path
-    if path_elements:
-      # Filter out the path elements that have a value of None
-      p = [i for i in path_elements if i]
-      if not path.endswith('/'):
-        path += '/'
-      path += '/'.join(p)
-
-    # Add any additional query parameters to the query string
-    if extra_params and len(extra_params) > 0:
-      extra_query = self._EncodeParameters(extra_params)
-      # Add it to the existing query
-      if query:
-        query += '&' + extra_query
-      else:
-        query = extra_query
-
-    # Return the rebuilt URL
-    return urlparse.urlunparse((scheme, netloc, path, params, query, fragment))
-
-  def _InitializeRequestHeaders(self, request_headers):
-    if request_headers:
-      self._request_headers = request_headers
-    else:
-      self._request_headers = {}
-
-  def _InitializeUserAgent(self):
-    user_agent = 'Python-urllib/%s (python-twitter/%s)' % \
-                 (self._urllib.__version__, __version__)
-    self.SetUserAgent(user_agent)
-
-  def _InitializeDefaultParameters(self):
-    self._default_params = {}
-
-  def _AddAuthorizationHeader(self, username, password):
-    if username and password:
-      basic_auth = base64.encodestring('%s:%s' % (username, password))[:-1]
-      self._request_headers['Authorization'] = 'Basic %s' % basic_auth
-
-  def _RemoveAuthorizationHeader(self):
-    if self._request_headers and 'Authorization' in self._request_headers:
-      del self._request_headers['Authorization']
-
-  def _DecompressGzippedResponse(self, response):
-    raw_data = response.read()
-    if response.headers.get('content-encoding', None) == 'gzip':
-      url_data = gzip.GzipFile(fileobj=StringIO.StringIO(raw_data)).read()
-    else:
-      url_data = raw_data
-    return url_data
-
-  def _GetOpener(self, url, username=None, password=None):
-    if username and password:
-      self._AddAuthorizationHeader(username, password)
-      handler = self._urllib.HTTPBasicAuthHandler()
-      (scheme, netloc, path, params, query, fragment) = urlparse.urlparse(url)
-      handler.add_password(Api._API_REALM, netloc, username, password)
-      opener = self._urllib.build_opener(handler)
-    else:
-      opener = self._urllib.build_opener()
-    opener.addheaders = self._request_headers.items()
-    return opener
-
-  def _Encode(self, s):
-    if self._input_encoding:
-      return unicode(s, self._input_encoding).encode('utf-8')
-    else:
-      return unicode(s).encode('utf-8')
-
-  def _EncodeParameters(self, parameters):
-    '''Return a string in key=value&key=value form
-
-    Values of None are not included in the output string.
-
-    @param parameters: A dict of (key, value) tuples, where value is encoded as
-        specified by self._encoding
-    @returns: A URL-encoded string in "key=value&key=value" form
-    '''
-    if parameters is None:
-      return None
-    else:
-      return urllib.urlencode(dict([(k, self._Encode(v)) for k, v in parameters.items() if v is not None]))
-
-  def _EncodePostData(self, post_data):
-    '''Return a string in key=value&key=value form
-
-    Values are assumed to be encoded in the format specified by self._encoding,
-    and are subsequently URL encoded.
-
-    @param post_data: A dict of (key, value) tuples, where value is encoded as
-        specified by self._encoding
-    @returns: A URL-encoded string in "key=value&key=value" form
-    '''
-    if post_data is None:
-      return None
-    else:
-      return urllib.urlencode(dict([(k, self._Encode(v)) for k, v in post_data.items()]))
-
-  def _CheckForTwitterError(self, data):
-    """Raises a TwitterError if twitter returns an error message.
-
-    @param data: A python dict created from the Twitter json response
-    @raises: TwitterError wrapping the twitter error message if one exists.
-    """
-    # Twitter errors are relatively unlikely, so it is faster
-    # to check first, rather than try and catch the exception
-    if 'error' in data:
-      raise TwitterError(data['error'])
-
-  def _FetchUrl(self,
-                url,
-                post_data=None,
-                parameters=None,
-                no_cache=None,
-                use_gzip_compression=None):
-    '''Fetch a URL, optionally caching for a specified time.
-
-    @param url: The URL to retrieve
-    @param post_data: A dict of (str, unicode) key/value pairs.
-        If set, POST will be used.
-    @param parameters: A dict whose key/value pairs should encoded and added
-        to the query string. [optional]
-    @param no_cache: If true, overrides the cache on the current request
-    @param use_gzip_compression: If True, tells the server to gzip-compress the
-        response. It does not apply to POST requests.
-        Defaults to None, which will get the value to use from
-        the instance variable self._use_gzip [optional]
-
-    @returns: A string containing the body of the response.
-    '''
-    # Build the extra parameters dict
-    extra_params = {}
-    if self._default_params:
-      extra_params.update(self._default_params)
-    if parameters:
-      extra_params.update(parameters)
-
-    # Add key/value parameters to the query string of the url
-    url = self._BuildUrl(url, extra_params=extra_params)
-
-    # Get a url opener that can handle basic auth
-    opener = self._GetOpener(url, username=self._username, password=self._password)
-
-    if use_gzip_compression is None:
-      use_gzip = self._use_gzip
-    else:
-      use_gzip = use_gzip_compression
-      
-    # Set up compression
-    if use_gzip and not post_data:
-      opener.addheaders.append(('Accept-Encoding', 'gzip'))
-
-    encoded_post_data = self._EncodePostData(post_data)
-
-    # Open and return the URL immediately if we're not going to cache
-    if encoded_post_data or no_cache or not self._cache or not self._cache_timeout:
-      response = opener.open(url, encoded_post_data)
-      url_data = self._DecompressGzippedResponse(response)
-      opener.close()
-    else:
-      # Unique keys are a combination of the url and the username
-      if self._username:
-        key = self._username + ':' + url
-      else:
-        key = url
-
-      # See if it has been cached before
-      last_cached = self._cache.GetCachedTime(key)
-
-      # If the cached version is outdated then fetch another and store it
-      if not last_cached or time.time() >= last_cached + self._cache_timeout:
-        response = opener.open(url, encoded_post_data)
-        url_data = self._DecompressGzippedResponse(response)
-        opener.close()
-        self._cache.Set(key, url_data)
-      else:
-        url_data = self._cache.Get(key)
-
-    # Always return the latest version
-    return url_data
+        '''Returns the 20 most recent mentions (status containing @username)
+        for the authenticating user.
+
+        @param since_id: Returns only public statuses with an ID greater than
+            (that is, more recent than) the specified ID. [optional]
+
+        @param max_id: Returns only statuses with an ID less than
+            (that is, older than) the specified ID.  [optional]
+
+        @param page: Retrieves the 20 next most recent replies. [optional]
+
+        @returns: A sequence of twitter.Status instances, one for each mention
+            of the user. see:
+            http://apiwiki.twitter.com/REST-API-Documentation#statuses/mentions
+        '''
+
+        url = '%s/statuses/mentions.json' % self.base_url
+
+        if not self._username:
+            raise TwitterError("The twitter.Api instance must be \
+                                                               authenticated.")
+
+        parameters = {}
+
+        if since_id:
+            parameters['since_id'] = since_id
+        if max_id:
+            parameters['max_id'] = max_id
+        if page:
+            parameters['page'] = page
+
+        json = self._FetchUrl(url, parameters=parameters)
+        data = json.loads(json)
+
+        self._CheckForTwitterError(data)
+
+        return [Status.NewFromJsonDict(x) for x in data]
+
+    def GetUserByEmail(self, email):
+        '''Returns a single user by email address.
+
+        @param email: The email of the user to retrieve.
+        @returns: A twitter.User instance representing that user
+        '''
+        url = '%s/users/show.json?email=%s' % (self.base_url, email)
+        json = self._FetchUrl(url)
+        data = json.loads(json)
+        self._CheckForTwitterError(data)
+        return User.NewFromJsonDict(data)
+
+    def VerifyCredentials(self):
+        '''Returns a twitter.User instance if the authenticating user is valid.
+
+        @returns: A twitter.User instance representing that user if the
+        credentials are valid, None otherwise.
+        '''
+        if not self._username:
+            raise TwitterError("Api instance must first be given user \
+                                                                credentials.")
+        url = '%s/account/verify_credentials.json' % self.base_url
+        try:
+            json = self._FetchUrl(url, no_cache=True)
+        except urllib2.HTTPError, http_error:
+            if http_error.code == httplib.UNAUTHORIZED:
+                return None
+            else:
+                raise http_error
+        data = json.loads(json)
+        self._CheckForTwitterError(data)
+        return User.NewFromJsonDict(data)
+
+    def SetCredentials(self, username, password):
+        '''Set the username and password for this instance
+
+        @param username: The twitter username.
+        @param password: The twitter password.
+        '''
+        self._username = username
+        self._password = password
+
+    def ClearCredentials(self):
+        '''Clear the username and password for this instance
+        '''
+        self._username = None
+        self._password = None
+
+    def SetCache(self, cache):
+        '''Override the default cache.  Set to None to prevent caching.
+
+        @param cache: an instance that supports the same API as the
+                      twitter._FileCache
+        '''
+        if cache == DEFAULT_CACHE:
+            self._cache = _FileCache()
+        else:
+            self._cache = cache
+
+    def SetUrllib(self, urllib):
+        '''Override the default urllib implementation.
+
+        @param urllib: an instance that supports the same API as the urllib2
+                       module
+        '''
+        self._urllib = urllib
+
+    def SetCacheTimeout(self, cache_timeout):
+        '''Override the default cache timeout.
+
+        @param cache_timeout: time, in seconds, that responses should be reused
+        '''
+        self._cache_timeout = cache_timeout
+
+    def SetUserAgent(self, user_agent):
+        '''Override the default user agent
+
+        @param user_agent: a string that should be send to the server as the
+                           User-agent
+        '''
+        self._request_headers['User-Agent'] = user_agent
+
+    def SetXTwitterHeaders(self, client, url, version):
+        '''Set the X-Twitter HTTP headers that will be sent to the server.
+
+        @param client: The client name as a string.  Will be sent to the server
+            as the 'X-Twitter-Client' header.
+        @param url: The URL of the meta.xml as a string.  Will be sent to the
+            server as the 'X-Twitter-Client-URL' header.
+        @param version: The client version as a string.  Will be sent to the
+            server as the 'X-Twitter-Client-Version' header.
+        '''
+        self._request_headers['X-Twitter-Client'] = client
+        self._request_headers['X-Twitter-Client-URL'] = url
+        self._request_headers['X-Twitter-Client-Version'] = version
+
+    def SetSource(self, source):
+        '''Suggest the "from source" value to be displayed on the Twitter
+        web site.
+
+        The value of the 'source' parameter must be first recognized by
+        the Twitter server.  New source values are authorized on a case by
+        case basis by the Twitter development team.
+
+        @param source: The source name as a string.  Will be sent to the server
+            as the 'source' parameter.
+        '''
+        self._default_params['source'] = source
+
+    def GetRateLimitStatus(self):
+        '''Fetch the rate limit status for the currently authorized user.
+
+        @returns: A dictionary containing the time the limit will reset
+            (reset_time), the number of remaining hits allowed before the reset
+            (remaining_hits), the number of hits allowed in a 60-minute period
+            (hourly_limit), and the time of the reset in seconds since The
+            Epoch (reset_time_in_seconds).
+        '''
+        url = '%s/account/rate_limit_status.json' % self.base_url
+        json = self._FetchUrl(url, no_cache=True)
+        data = json.loads(json)
+
+        self._CheckForTwitterError(data)
+
+        return data
+
+    def MaximumHitFrequency(self):
+        '''Determines the minimum number of seconds that a program must wait
+        before hitting the server again without exceeding the rate_limit
+        imposed for the currently authenticated user.
+
+        @returns: The minimum second interval that a program must use so as to
+                  not exceed the rate_limit imposed for the user.
+        '''
+        rate_status = self.GetRateLimitStatus()
+        reset_time = rate_status.get('reset_time', None)
+        limit = rate_status.get('remaining_hits', None)
+
+        if reset_time and limit:
+            # put the reset time into a datetime object
+            reset = datetime.datetime(*rfc822.parsedate(reset_time)[:7])
+
+            # find the difference in time between now and the reset time + 1
+            # hour
+            utc_now = datetime.datetime.utcnow()
+            delta = reset + datetime.timedelta(hours=1) - utc_now
+
+            # determine the minimum number of seconds allowed as a regular
+            # interval
+            max_frequency = int(delta.seconds / limit)
+
+            # return the number of seconds
+            return max_frequency
+
+        return 0
+
+    def _BuildUrl(self, url, path_elements=None, extra_params=None):
+        # Break url into consituent parts
+        parsed_url = urlparse.urlparse(url)
+        (scheme, netloc, path, params, query, fragment) = parsed_url
+
+        # Add any additional path elements to the path
+        if path_elements:
+            # Filter out the path elements that have a value of None
+            p = [i for i in path_elements if i]
+            if not path.endswith('/'):
+                path += '/'
+            path += '/'.join(p)
+
+        # Add any additional query parameters to the query string
+        if extra_params and len(extra_params) > 0:
+            extra_query = self._EncodeParameters(extra_params)
+        # Add it to the existing query
+        if query:
+            query += '&' + extra_query
+        else:
+            query = extra_query
+
+        # Return the rebuilt URL
+        return urlparse.urlunparse((scheme, netloc, path, params, query,
+                                                                    fragment))
+
+    def _InitializeRequestHeaders(self, request_headers):
+        if request_headers:
+            self._request_headers = request_headers
+        else:
+            self._request_headers = {}
+
+    def _InitializeUserAgent(self):
+        user_agent = 'Python-urllib/%s (python-twitter/%s)' % \
+                     (self._urllib.__version__, __version__)
+        self.SetUserAgent(user_agent)
+
+    def _InitializeDefaultParameters(self):
+        self._default_params = {}
+
+    def _AddAuthorizationHeader(self, username, password):
+        if username and password:
+            basic_auth = base64.encodestring('%s:%s' % \
+                                                    (username, password))[:-1]
+            self._request_headers['Authorization'] = 'Basic %s' % basic_auth
+
+    def _RemoveAuthorizationHeader(self):
+        if self._request_headers and 'Authorization' in self._request_headers:
+            del self._request_headers['Authorization']
+
+    def _DecompressGzippedResponse(self, response):
+        raw_data = response.read()
+        if response.headers.get('content-encoding', None) == 'gzip':
+            url_data = gzip.GzipFile(fileobj=StringIO.StringIO(raw_data))\
+                                                                      .read()
+        else:
+            url_data = raw_data
+        return url_data
+
+    def _GetOpener(self, url, username=None, password=None):
+        if username and password:
+            self._AddAuthorizationHeader(username, password)
+            handler = self._urllib.HTTPBasicAuthHandler()
+            parsed_url = urlparse.urlparse(url)
+            (scheme, netloc, path, params, query, fragment) = parsed_url
+            handler.add_password(Api._API_REALM, netloc, username, password)
+            opener = self._urllib.build_opener(handler)
+        else:
+            opener = self._urllib.build_opener()
+        opener.addheaders = self._request_headers.items()
+        return opener
+
+    def _Encode(self, s):
+        if self._input_encoding:
+            return unicode(s, self._input_encoding).encode('utf-8')
+        else:
+            return unicode(s).encode('utf-8')
+
+    def _EncodeParameters(self, parameters):
+        '''Return a string in key=value&key=value form
+
+        Values of None are not included in the output string.
+
+        @param parameters: A dict of (key, value) tuples, where value is
+            encoded as specified by self._encoding
+        @returns: A URL-encoded string in "key=value&key=value" form
+        '''
+        if parameters is None:
+            return None
+        else:
+            return urllib.urlencode(dict([(k, self._Encode(v)) for k, v in \
+                                        parameters.items() if v is not None]))
+
+    def _EncodePostData(self, post_data):
+        '''Return a string in key=value&key=value form
+
+        Values are assumed to be encoded in the format specified by
+        self._encoding, and are subsequently URL encoded.
+
+        @param post_data: A dict of (key, value) tuples, where value is
+            encoded as specified by self._encoding
+        @returns: A URL-encoded string in "key=value&key=value" form
+        '''
+        if post_data is None:
+            return None
+        else:
+            return urllib.urlencode(dict([(k, self._Encode(v)) for k, v in \
+                                                          post_data.items()]))
+
+    def _CheckForTwitterError(self, data):
+        """Raises a TwitterError if twitter returns an error message.
+
+        @param data: A python dict created from the Twitter json response
+        @raises: TwitterError wrapping the twitter error message if one exists.
+        """
+        # Twitter errors are relatively unlikely, so it is faster
+        # to check first, rather than try and catch the exception
+        if 'error' in data:
+            raise TwitterError(data['error'])
+
+    def _FetchUrl(self,
+                    url,
+                    post_data=None,
+                    parameters=None,
+                    no_cache=None,
+                    use_gzip_compression=None):
+        '''Fetch a URL, optionally caching for a specified time.
+
+        @param url: The URL to retrieve
+        @param post_data: A dict of (str, unicode) key/value pairs.
+            If set, POST will be used.
+        @param parameters: A dict whose key/value pairs should encoded and
+            added to the query string. [optional]
+        @param no_cache: If true, overrides the cache on the current request
+        @param use_gzip_compression: If True, tells the server to gzip-compress
+                               the response. It does not apply to POST requests
+            Defaults to None, which will get the value to use from
+            the instance variable self._use_gzip [optional]
+
+        @returns: A string containing the body of the response.
+        '''
+        # Build the extra parameters dict
+        extra_params = {}
+        if self._default_params:
+            extra_params.update(self._default_params)
+        if parameters:
+            extra_params.update(parameters)
+
+        # Add key/value parameters to the query string of the url
+        url = self._BuildUrl(url, extra_params=extra_params)
+
+        # Get a url opener that can handle basic auth
+        opener = self._GetOpener(url, username=self._username,
+                                                    password=self._password)
+
+        if use_gzip_compression is None:
+            use_gzip = self._use_gzip
+        else:
+            use_gzip = use_gzip_compression
+
+        # Set up compression
+        if use_gzip and not post_data:
+            opener.addheaders.append(('Accept-Encoding', 'gzip'))
+
+        encoded_post_data = self._EncodePostData(post_data)
+
+        # Open and return the URL immediately if we're not going to cache
+        if encoded_post_data or no_cache or not self._cache or \
+                                                   not self._cache_timeout:
+            response = opener.open(url, encoded_post_data)
+            url_data = self._DecompressGzippedResponse(response)
+            opener.close()
+        else:
+            # Unique keys are a combination of the url and the username
+            if self._username:
+                key = self._username + ':' + url
+            else:
+                key = url
+
+            # See if it has been cached before
+            last_cached = self._cache.GetCachedTime(key)
+
+            # If the cached version is outdated then fetch another and store it
+            if not last_cached or time.time() >= last_cached + \
+                                                           self._cache_timeout:
+                response = opener.open(url, encoded_post_data)
+                url_data = self._DecompressGzippedResponse(response)
+                opener.close()
+                self._cache.Set(key, url_data)
+            else:
+                url_data = self._cache.Get(key)
+
+        # Always return the latest version
+        return url_data
 
 
 class _FileCacheError(Exception):
-  '''Base exception class for FileCache related errors'''
+    '''Base exception class for FileCache related errors'''
+
 
 class _FileCache(object):
 
-  DEPTH = 3
-
-  def __init__(self,root_directory=None):
-    self._InitializeRootDirectory(root_directory)
-
-  def Get(self,key):
-    path = self._GetPath(key)
-    if os.path.exists(path):
-      return open(path).read()
-    else:
-      return None
-
-  def Set(self,key,data):
-    path = self._GetPath(key)
-    directory = os.path.dirname(path)
-    if not os.path.exists(directory):
-      os.makedirs(directory)
-    if not os.path.isdir(directory):
-      raise _FileCacheError('%s exists but is not a directory' % directory)
-    temp_fd, temp_path = tempfile.mkstemp()
-    temp_fp = os.fdopen(temp_fd, 'w')
-    temp_fp.write(data)
-    temp_fp.close()
-    if not path.startswith(self._root_directory):
-      raise _FileCacheError('%s does not appear to live under %s' %
-                            (path, self._root_directory))
-    if os.path.exists(path):
-      os.remove(path)
-    os.rename(temp_path, path)
-
-  def Remove(self,key):
-    path = self._GetPath(key)
-    if not path.startswith(self._root_directory):
-      raise _FileCacheError('%s does not appear to live under %s' %
-                            (path, self._root_directory ))
-    if os.path.exists(path):
-      os.remove(path)
-
-  def GetCachedTime(self,key):
-    path = self._GetPath(key)
-    if os.path.exists(path):
-      return os.path.getmtime(path)
-    else:
-      return None
-
-  def _GetUsername(self):
-    '''Attempt to find the username in a cross-platform fashion.'''
-    try:
-      return os.getenv('USER') or \
-             os.getenv('LOGNAME') or \
-             os.getenv('USERNAME') or \
-             os.getlogin() or \
-             'nobody'
-    except (IOError, OSError), e:
-      return 'nobody'
-
-  def _GetTmpCachePath(self):
-    username = self._GetUsername()
-    cache_directory = 'python.cache_' + username
-    return os.path.join(tempfile.gettempdir(), cache_directory)
-
-  def _InitializeRootDirectory(self, root_directory):
-    if not root_directory:
-      root_directory = self._GetTmpCachePath()
-    root_directory = os.path.abspath(root_directory)
-    if not os.path.exists(root_directory):
-      os.mkdir(root_directory)
-    if not os.path.isdir(root_directory):
-      raise _FileCacheError('%s exists but is not a directory' %
-                            root_directory)
-    self._root_directory = root_directory
-
-  def _GetPath(self,key):
-    try:
-        hashed_key = md5(key).hexdigest()
-    except TypeError:
-        hashed_key = md5.new(key).hexdigest()
-        
-    return os.path.join(self._root_directory,
-                        self._GetPrefix(hashed_key),
-                        hashed_key)
-
-  def _GetPrefix(self,hashed_key):
-    return os.path.sep.join(hashed_key[0:_FileCache.DEPTH])
+    DEPTH = 3
+
+    def __init__(self, root_directory=None):
+        self._InitializeRootDirectory(root_directory)
+
+    def Get(self, key):
+        path = self._GetPath(key)
+        if os.path.exists(path):
+            return open(path).read()
+        else:
+            return None
+
+    def Set(self, key, data):
+        path = self._GetPath(key)
+        directory = os.path.dirname(path)
+        if not os.path.exists(directory):
+            os.makedirs(directory)
+        if not os.path.isdir(directory):
+            raise _FileCacheError('%s exists but is not a directory' \
+                                                                  % directory)
+        temp_fd, temp_path = tempfile.mkstemp()
+        temp_fp = os.fdopen(temp_fd, 'w')
+        temp_fp.write(data)
+        temp_fp.close()
+        if not path.startswith(self._root_directory):
+            raise _FileCacheError('%s does not appear to live under %s' %
+                                (path, self._root_directory))
+        if os.path.exists(path):
+            os.remove(path)
+        os.rename(temp_path, path)
+
+    def Remove(self, key):
+        path = self._GetPath(key)
+        if not path.startswith(self._root_directory):
+            raise _FileCacheError('%s does not appear to live under %s' %
+                                 (path, self._root_directory))
+        if os.path.exists(path):
+            os.remove(path)
+
+    def GetCachedTime(self, key):
+        path = self._GetPath(key)
+        if os.path.exists(path):
+            return os.path.getmtime(path)
+        else:
+            return None
+
+    def _GetUsername(self):
+        '''Attempt to find the username in a cross-platform fashion.'''
+        try:
+            return os.getenv('USER') or \
+                   os.getenv('LOGNAME') or \
+                   os.getenv('USERNAME') or \
+                   os.getlogin() or \
+                   'nobody'
+        except (IOError, OSError), e:
+            return 'nobody'
+
+    def _GetTmpCachePath(self):
+        username = self._GetUsername()
+        cache_directory = 'python.cache_' + username
+        return os.path.join(tempfile.gettempdir(), cache_directory)
+
+    def _InitializeRootDirectory(self, root_directory):
+        if not root_directory:
+            root_directory = self._GetTmpCachePath()
+        root_directory = os.path.abspath(root_directory)
+        if not os.path.exists(root_directory):
+            os.mkdir(root_directory)
+        if not os.path.isdir(root_directory):
+            raise _FileCacheError('%s exists but is not a directory' %
+                                  root_directory)
+        self._root_directory = root_directory
+
+    def _GetPath(self, key):
+        try:
+            hashed_key = md5(key).hexdigest()
+        except TypeError:
+            hashed_key = md5.new(key).hexdigest()
+
+        return os.path.join(self._root_directory,
+                            self._GetPrefix(hashed_key),
+                            hashed_key)
+
+    def _GetPrefix(self, hashed_key):
+        return os.path.sep.join(hashed_key[0:_FileCache.DEPTH])