Commits

Anonymous committed fd973ab

sina weibo api, using oauth1.0

Comments (0)

Files changed (1)

+#!/usr/bin/python2.7
+#
+# Copyright 2007 The Python-Weibo Developers
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+'''A library that provides a Python interface to the weibo API'''
+
+__version__ = '0.8.2'
+
+
+import base64
+import calendar
+import datetime
+import httplib
+import os
+import rfc822
+import sys
+import tempfile
+import textwrap
+import time
+import calendar
+import urllib
+import urllib2
+import urlparse
+import gzip
+import StringIO
+
+try:
+  # Python >= 2.6
+  import json as simplejson
+except ImportError:
+  try:
+    # Python < 2.6
+    import simplejson
+  except ImportError:
+    try:
+      # Google App Engine
+      from django.utils import simplejson
+    except ImportError:
+      raise ImportError, "Unable to load a json library"
+
+# parse_qsl moved to urlparse module in v2.6
+try:
+  from urlparse import parse_qsl, parse_qs
+except ImportError:
+  from cgi import parse_qsl, parse_qs
+
+try:
+  from hashlib import md5
+except ImportError:
+  from md5 import md5
+
+import oauth2 as oauth
+
+
+CHARACTER_LIMIT = 140
+
+# A singleton representing a lazily instantiated FileCache.
+DEFAULT_CACHE = object()
+
+WEIBO_SERVER = 'api.t.sina.com.cn'
+REQUEST_TOKEN_URL = 'http://%s/oauth/request_token' % WEIBO_SERVER
+ACCESS_TOKEN_URL  = 'http://%s/oauth/access_token' % WEIBO_SERVER
+AUTHORIZATION_URL = 'http://%s/oauth/authorize' 
+
+
+
+class WeiboError(Exception):
+  '''Base class for Weibo 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 Weibo 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
+    status.urls
+    status.user_mentions
+    status.hashtags
+    status.geo
+    status.place
+    status.coordinates
+    status.contributors
+  '''
+  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,
+               urls=None,
+               user_mentions=None,
+               hashtags=None,
+               geo=None,
+               place=None,
+               coordinates=None,
+               contributors=None,
+               retweeted=None,
+               retweeted_status=None,
+               retweet_count=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"
+
+    Args:
+      created_at:
+        The time this status message was posted. [Optional]
+      favorited:
+        Whether this is a favorite of the authenticated user. [Optional]
+      id:
+        The unique id of this status message. [Optional]
+      text:
+        The text of this status message. [Optional]
+      location:
+        the geolocation string associated with this message. [Optional]
+      relative_created_at:
+        A human readable string representing the posting time. [Optional]
+      user:
+        A twitter.User instance representing the person posting the
+        message. [Optional]
+      now:
+        The current time, if the client choses to set it.
+        Defaults to the wall clock time. [Optional]
+      urls:
+      user_mentions:
+      hashtags:
+      geo:
+      place:
+      coordinates:
+      contributors:
+      retweeted:
+      retweeted_status:
+      retweet_count:
+    '''
+    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.retweeted = retweeted
+    self.source = source
+    self.urls = urls
+    self.user_mentions = user_mentions
+    self.hashtags = hashtags
+    self.geo = geo
+    self.place = place
+    self.coordinates = coordinates
+    self.contributors = contributors
+    self.retweeted_status = retweeted_status
+    self.retweet_count = retweet_count
+
+  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.
+
+    Args:
+      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.
+
+    Args:
+      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.
+
+    Args:
+      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 GetRetweeted(self):
+    return self._retweeted
+
+  def SetRetweeted(self, retweeted):
+    self._retweeted = retweeted
+
+  retweeted = property(GetRetweeted, SetRetweeted,
+                       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.
+
+    Args:
+      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
+
+    Args:
+      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.
+
+    Args:
+      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.
+
+    Args:
+      now:
+        The wallclock time for this instance.
+    '''
+    self._now = now
+
+  now = property(GetNow, SetNow,
+                 doc='The wallclock time for this status instance.')
+
+  def GetGeo(self):
+    return self._geo
+
+  def SetGeo(self, geo):
+    self._geo = geo
+
+  geo = property(GetGeo, SetGeo,
+                 doc='')
+
+  def GetPlace(self):
+    return self._place
+
+  def SetPlace(self, place):
+    self._place = place
+
+  place = property(GetPlace, SetPlace,
+                   doc='')
+
+  def GetCoordinates(self):
+    return self._coordinates
+
+  def SetCoordinates(self, coordinates):
+    self._coordinates = coordinates
+
+  coordinates = property(GetCoordinates, SetCoordinates,
+                         doc='')
+
+  def GetContributors(self):
+    return self._contributors
+
+  def SetContributors(self, contributors):
+    self._contributors = contributors
+
+  contributors = property(GetContributors, SetContributors,
+                          doc='')
+
+  def GetRetweeted_status(self):
+    return self._retweeted_status
+
+  def SetRetweeted_status(self, retweeted_status):
+    self._retweeted_status = retweeted_status
+
+  retweeted_status = property(GetRetweeted_status, SetRetweeted_status,
+                              doc='')
+
+  def GetRetweetCount(self):
+    return self._retweet_count
+
+  def SetRetweetCount(self, retweet_count):
+    self._retweet_count = retweet_count
+
+  retweet_count = property(GetRetweetCount, SetRetweetCount,
+                           doc='')
+
+  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.retweeted == other.retweeted and \
+             self.favorited == other.favorited and \
+             self.source == other.source and \
+             self.geo == other.geo and \
+             self.place == other.place and \
+             self.coordinates == other.coordinates and \
+             self.contributors == other.contributors and \
+             self.retweeted_status == other.retweeted_status and \
+             self.retweet_count == other.retweet_count
+    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 simplejson.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.retweeted is not None:
+      data['retweeted'] = self.retweeted
+    if self.favorited is not None:
+      data['favorited'] = self.favorited
+    if self.source:
+      data['source'] = self.source
+    if self.geo:
+      data['geo'] = self.geo
+    if self.place:
+      data['place'] = self.place
+    if self.coordinates:
+      data['coordinates'] = self.coordinates
+    if self.contributors:
+      data['contributors'] = self.contributors
+    if self.hashtags:
+      data['hashtags'] = [h.text for h in self.hashtags]
+    if self.retweeted_status:
+      data['retweeted_status'] = self.retweeted_status.AsDict()
+    if self.retweet_count:
+      data['retweet_count'] = self.retweet_count
+    return data
+
+  @staticmethod
+  def NewFromJsonDict(data):
+    '''Create a new instance based on a JSON dict.
+
+    Args:
+      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
+    if 'retweeted_status' in data:
+      retweeted_status = Status.NewFromJsonDict(data['retweeted_status'])
+    else:
+      retweeted_status = None
+    urls = None
+    user_mentions = None
+    hashtags = None
+    if 'entities' in data:
+      if 'urls' in data['entities']:
+        urls = [Url.NewFromJsonDict(u) for u in data['entities']['urls']]
+      if 'user_mentions' in data['entities']:
+        user_mentions = [User.NewFromJsonDict(u) for u in data['entities']['user_mentions']]
+      if 'hashtags' in data['entities']:
+        hashtags = [Hashtag.NewFromJsonDict(h) for h in data['entities']['hashtags']]
+    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),
+                  retweeted=data.get('retweeted', None),
+                  source=data.get('source', None),
+                  user=user,
+                  urls=urls,
+                  user_mentions=user_mentions,
+                  hashtags=hashtags,
+                  geo=data.get('geo', None),
+                  place=data.get('place', None),
+                  coordinates=data.get('coordinates', None),
+                  contributors=data.get('contributors', None),
+                  retweeted_status=retweeted_status,
+                  retweet_count=data.get('retweet_count', None))
+
+
+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
+    user.geo_enabled
+    user.verified
+    user.lang
+    user.notifications
+    user.contributors_enabled
+    user.created_at
+    user.listed_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,
+               geo_enabled=None,
+               verified=None,
+               lang=None,
+               notifications=None,
+               contributors_enabled=None,
+               created_at=None,
+               listed_count=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
+    self.geo_enabled = geo_enabled
+    self.verified = verified
+    self.lang = lang
+    self.notifications = notifications
+    self.contributors_enabled = contributors_enabled
+    self.created_at = created_at
+    self.listed_count = listed_count
+
+  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.
+
+    Args:
+      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.
+
+    Args:
+      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 twitter name of this user.
+
+    Returns:
+      The short twitter name of this user
+    '''
+    return self._screen_name
+
+  def SetScreenName(self, screen_name):
+    '''Set the short twitter name of this user.
+
+    Args:
+      screen_name: the short twitter name of this user
+    '''
+    self._screen_name = screen_name
+
+  screen_name = property(GetScreenName, SetScreenName,
+                         doc='The short twitter name 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.
+
+    Args:
+      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.
+
+    Args:
+      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.
+
+    Args:
+      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.
+
+    Args:
+      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.
+
+    Args:
+      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.
+
+    Args:
+      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.
+
+    Args:
+      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.
+
+    Args:
+      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 GetListedCount(self):
+    '''Get the listed count for this user.
+
+    Returns:
+      The number of lists this user belongs to.
+    '''
+    return self._listed_count
+
+  def SetListedCount(self, count):
+    '''Set the listed count for this user.
+
+    Args:
+      count:
+        The number of lists this user belongs to.
+    '''
+    self._listed_count = count
+
+  listed_count = property(GetListedCount, SetListedCount,
+                          doc='The number of lists this user belongs to.')
+
+  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.
+
+    Args:
+      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.
+
+    Args:
+      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.
+
+    Args:
+      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 GetGeoEnabled(self):
+    '''Get the setting of geo_enabled for this user.
+
+    Returns:
+      True/False if Geo tagging is enabled
+    '''
+    return self._geo_enabled
+
+  def SetGeoEnabled(self, geo_enabled):
+    '''Set the latest twitter.geo_enabled of this user.
+
+    Args:
+      geo_enabled:
+        True/False if Geo tagging is to be enabled
+    '''
+    self._geo_enabled = geo_enabled
+
+  geo_enabled = property(GetGeoEnabled, SetGeoEnabled,
+                         doc='The value of twitter.geo_enabled for this user.')
+
+  def GetVerified(self):
+    '''Get the setting of verified for this user.
+
+    Returns:
+      True/False if user is a verified account
+    '''
+    return self._verified
+
+  def SetVerified(self, verified):
+    '''Set twitter.verified for this user.
+
+    Args:
+      verified:
+        True/False if user is a verified account
+    '''
+    self._verified = verified
+
+  verified = property(GetVerified, SetVerified,
+                      doc='The value of twitter.verified for this user.')
+
+  def GetLang(self):
+    '''Get the setting of lang for this user.
+
+    Returns:
+      language code of the user
+    '''
+    return self._lang
+
+  def SetLang(self, lang):
+    '''Set twitter.lang for this user.
+
+    Args:
+      lang:
+        language code for the user
+    '''
+    self._lang = lang
+
+  lang = property(GetLang, SetLang,
+                  doc='The value of twitter.lang for this user.')
+
+  def GetNotifications(self):
+    '''Get the setting of notifications for this user.
+
+    Returns:
+      True/False for the notifications setting of the user
+    '''
+    return self._notifications
+
+  def SetNotifications(self, notifications):
+    '''Set twitter.notifications for this user.
+
+    Args:
+      notifications:
+        True/False notifications setting for the user
+    '''
+    self._notifications = notifications
+
+  notifications = property(GetNotifications, SetNotifications,
+                           doc='The value of twitter.notifications for this user.')
+
+  def GetContributorsEnabled(self):
+    '''Get the setting of contributors_enabled for this user.
+
+    Returns:
+      True/False contributors_enabled of the user
+    '''
+    return self._contributors_enabled
+
+  def SetContributorsEnabled(self, contributors_enabled):
+    '''Set twitter.contributors_enabled for this user.
+
+    Args:
+      contributors_enabled:
+        True/False contributors_enabled setting for the user
+    '''
+    self._contributors_enabled = contributors_enabled
+
+  contributors_enabled = property(GetContributorsEnabled, SetContributorsEnabled,
+                                  doc='The value of twitter.contributors_enabled for this user.')
+
+  def GetCreatedAt(self):
+    '''Get the setting of created_at for this user.
+
+    Returns:
+      created_at value of the user
+    '''
+    return self._created_at
+
+  def SetCreatedAt(self, created_at):
+    '''Set twitter.created_at for this user.
+
+    Args:
+      created_at:
+        created_at value for the user
+    '''
+    self._created_at = created_at
+
+  created_at = property(GetCreatedAt, SetCreatedAt,
+                        doc='The value of twitter.created_at 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 and \
+             self.geo_enabled == other.geo_enabled and \
+             self.verified == other.verified and \
+             self.lang == other.lang and \
+             self.notifications == other.notifications and \
+             self.contributors_enabled == other.contributors_enabled and \
+             self.created_at == other.created_at and \
+             self.listed_count == other.listed_count
+
+    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 simplejson.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
+    if self.geo_enabled:
+      data['geo_enabled'] = self.geo_enabled
+    if self.verified:
+      data['verified'] = self.verified
+    if self.lang:
+      data['lang'] = self.lang
+    if self.notifications:
+      data['notifications'] = self.notifications
+    if self.contributors_enabled:
+      data['contributors_enabled'] = self.contributors_enabled
+    if self.created_at:
+      data['created_at'] = self.created_at
+    if self.listed_count:
+      data['listed_count'] = self.listed_count
+
+    return data
+
+  @staticmethod
+  def NewFromJsonDict(data):
+    '''Create a new instance based on a JSON dict.
+
+    Args:
+      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,
+                geo_enabled=data.get('geo_enabled', None),
+                verified=data.get('verified', None),
+                lang=data.get('lang', None),
+                notifications=data.get('notifications', None),
+                contributors_enabled=data.get('contributors_enabled', None),
+                created_at=data.get('created_at', None),
+                listed_count=data.get('listed_count', None))
+
+class List(object):
+  '''A class representing the List structure used by the twitter API.
+  
+  The List structure exposes the following properties:
+  
+    list.id
+    list.name
+    list.slug
+    list.description
+    list.full_name
+    list.mode
+    list.uri
+    list.member_count
+    list.subscriber_count
+    list.following
+  '''
+  def __init__(self,
+               id=None,
+               name=None,
+               slug=None,
+               description=None,
+               full_name=None,
+               mode=None,
+               uri=None,
+               member_count=None,
+               subscriber_count=None,
+               following=None,
+               user=None):
+    self.id = id
+    self.name = name
+    self.slug = slug
+    self.description = description
+    self.full_name = full_name
+    self.mode = mode
+    self.uri = uri
+    self.member_count = member_count
+    self.subscriber_count = subscriber_count
+    self.following = following
+    self.user = user
+
+  def GetId(self):
+    '''Get the unique id of this list.
+
+    Returns:
+      The unique id of this list
+    '''
+    return self._id
+
+  def SetId(self, id):
+    '''Set the unique id of this list.
+
+    Args:
+      id:
+        The unique id of this list.
+    '''
+    self._id = id
+
+  id = property(GetId, SetId,
+                doc='The unique id of this list.')
+
+  def GetName(self):
+    '''Get the real name of this list.
+
+    Returns:
+      The real name of this list
+    '''
+    return self._name
+
+  def SetName(self, name):
+    '''Set the real name of this list.
+
+    Args:
+      name:
+        The real name of this list
+    '''
+    self._name = name
+
+  name = property(GetName, SetName,
+                  doc='The real name of this list.')
+
+  def GetSlug(self):
+    '''Get the slug of this list.
+
+    Returns:
+      The slug of this list
+    '''
+    return self._slug
+
+  def SetSlug(self, slug):
+    '''Set the slug of this list.
+
+    Args:
+      slug:
+        The slug of this list.
+    '''
+    self._slug = slug
+
+  slug = property(GetSlug, SetSlug,
+                  doc='The slug of this list.')
+
+  def GetDescription(self):
+    '''Get the description of this list.
+
+    Returns:
+      The description of this list
+    '''
+    return self._description
+
+  def SetDescription(self, description):
+    '''Set the description of this list.
+
+    Args:
+      description:
+        The description of this list.
+    '''
+    self._description = description
+
+  description = property(GetDescription, SetDescription,
+                         doc='The description of this list.')
+
+  def GetFull_name(self):
+    '''Get the full_name of this list.
+
+    Returns:
+      The full_name of this list
+    '''
+    return self._full_name
+
+  def SetFull_name(self, full_name):
+    '''Set the full_name of this list.
+
+    Args:
+      full_name:
+        The full_name of this list.
+    '''
+    self._full_name = full_name
+
+  full_name = property(GetFull_name, SetFull_name,
+                       doc='The full_name of this list.')
+
+  def GetMode(self):
+    '''Get the mode of this list.
+
+    Returns:
+      The mode of this list
+    '''
+    return self._mode
+
+  def SetMode(self, mode):
+    '''Set the mode of this list.
+
+    Args:
+      mode:
+        The mode of this list.
+    '''
+    self._mode = mode
+
+  mode = property(GetMode, SetMode,
+                  doc='The mode of this list.')
+
+  def GetUri(self):
+    '''Get the uri of this list.
+
+    Returns:
+      The uri of this list
+    '''
+    return self._uri
+
+  def SetUri(self, uri):
+    '''Set the uri of this list.
+
+    Args:
+      uri:
+        The uri of this list.
+    '''
+    self._uri = uri
+
+  uri = property(GetUri, SetUri,
+                 doc='The uri of this list.')
+
+  def GetMember_count(self):
+    '''Get the member_count of this list.
+
+    Returns:
+      The member_count of this list
+    '''
+    return self._member_count
+
+  def SetMember_count(self, member_count):
+    '''Set the member_count of this list.
+
+    Args:
+      member_count:
+        The member_count of this list.
+    '''
+    self._member_count = member_count
+
+  member_count = property(GetMember_count, SetMember_count,
+                          doc='The member_count of this list.')
+
+  def GetSubscriber_count(self):
+    '''Get the subscriber_count of this list.
+
+    Returns:
+      The subscriber_count of this list
+    '''
+    return self._subscriber_count
+
+  def SetSubscriber_count(self, subscriber_count):
+    '''Set the subscriber_count of this list.
+
+    Args:
+      subscriber_count:
+        The subscriber_count of this list.
+    '''
+    self._subscriber_count = subscriber_count
+
+  subscriber_count = property(GetSubscriber_count, SetSubscriber_count,
+                              doc='The subscriber_count of this list.')
+
+  def GetFollowing(self):
+    '''Get the following status of this list.
+
+    Returns:
+      The following status of this list
+    '''
+    return self._following
+
+  def SetFollowing(self, following):
+    '''Set the following status of this list.
+
+    Args:
+      following:
+        The following of this list.
+    '''
+    self._following = following
+
+  following = property(GetFollowing, SetFollowing,
+                       doc='The following status of this list.')
+
+  def GetUser(self):
+    '''Get the user of this list.
+
+    Returns:
+      The owner of this list
+    '''
+    return self._user
+
+  def SetUser(self, user):
+    '''Set the user of this list.
+
+    Args:
+      user:
+        The owner of this list.
+    '''
+    self._user = user
+
+  user = property(GetUser, SetUser,
+                  doc='The owner of this list.')
+
+  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.slug == other.slug and \
+             self.description == other.description and \
+             self.full_name == other.full_name and \
+             self.mode == other.mode and \
+             self.uri == other.uri and \
+             self.member_count == other.member_count and \
+             self.subscriber_count == other.subscriber_count and \
+             self.following == other.following and \
+             self.user == other.user
+
+    except AttributeError:
+      return False
+
+  def __str__(self):
+    '''A string representation of this twitter.List instance.
+
+    The return value is the same as the JSON string representation.
+
+    Returns:
+      A string representation of this twitter.List instance.
+    '''
+    return self.AsJsonString()
+
+  def AsJsonString(self):
+    '''A JSON string representation of this twitter.List instance.
+
+    Returns:
+      A JSON string representation of this twitter.List instance
+   '''
+    return simplejson.dumps(self.AsDict(), sort_keys=True)
+
+  def AsDict(self):
+    '''A dict representation of this twitter.List instance.
+
+    The return value uses the same key names as the JSON representation.
+
+    Return:
+      A dict representing this twitter.List instance
+    '''
+    data = {}
+    if self.id:
+      data['id'] = self.id
+    if self.name:
+      data['name'] = self.name
+    if self.slug:
+      data['slug'] = self.slug
+    if self.description:
+      data['description'] = self.description
+    if self.full_name:
+      data['full_name'] = self.full_name
+    if self.mode:
+      data['mode'] = self.mode
+    if self.uri:
+      data['uri'] = self.uri
+    if self.member_count is not None:
+      data['member_count'] = self.member_count
+    if self.subscriber_count is not None:
+      data['subscriber_count'] = self.subscriber_count
+    if self.following is not None:
+      data['following'] = self.following
+    if self.user is not None:
+      data['user'] = self.user
+    return data
+
+  @staticmethod
+  def NewFromJsonDict(data):
+    '''Create a new instance based on a JSON dict.
+
+    Args:
+      data:
+        A JSON dict, as converted from the JSON in the twitter API
+
+    Returns:
+      A twitter.List instance
+    '''
+    if 'user' in data:
+      user = User.NewFromJsonDict(data['user'])
+    else:
+      user = None
+    return List(id=data.get('id', None),
+                name=data.get('name', None),
+                slug=data.get('slug', None),
+                description=data.get('description', None),
+                full_name=data.get('full_name', None),
+                mode=data.get('mode', None),
+                uri=data.get('uri', None),
+                member_count=data.get('member_count', None),
+                subscriber_count=data.get('subscriber_count', None),
+                following=data.get('following', None),
+                user=user)
+
+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"
+
+    Args:
+      id:
+        The unique id of this direct message. [Optional]
+      created_at:
+        The time this direct message was posted. [Optional]
+      sender_id:
+        The id of the twitter user that sent this message. [Optional]
+      sender_screen_name:
+        The name of the twitter user that sent this message. [Optional]
+      recipient_id:
+        The id of the twitter that received this message. [Optional]
+      recipient_screen_name:
+        The name of the twitter that received this message. [Optional]
+      text:
+        The text of this direct message. [Optional]
+    '''
+    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.
+
+    Args:
+      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.
+
+    Args:
+      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.
+
+    Args:
+      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.
+
+    Args:
+      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.
+
+    Args:
+      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.
+
+    Args:
+      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.
+
+    Args:
+      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 simplejson.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.
+
+    Return:
+      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.
+
+    Args:
+      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 Hashtag(object):
+  ''' A class represeinting a twitter hashtag
+  '''
+  def __init__(self,
+               text=None):
+    self.text = text
+
+  @staticmethod
+  def NewFromJsonDict(data):
+    '''Create a new instance based on a JSON dict.
+
+    Args:
+      data:
+        A JSON dict, as converted from the JSON in the twitter API
+
+    Returns:
+      A twitter.Hashtag instance
+    '''
+    return Hashtag(text = data.get('text', None))
+
+class Trend(object):
+  ''' A class representing a trending topic
+  '''
+  def __init__(self, name=None, query=None, timestamp=None):
+    self.name = name
+    self.query = query
+    self.timestamp = timestamp
+
+  def __str__(self):
+    return 'Name: %s\nQuery: %s\nTimestamp: %s\n' % (self.name, self.query, self.timestamp)
+
+  @staticmethod
+  def NewFromJsonDict(data, timestamp = None):
+    '''Create a new instance based on a JSON dict
+
+    Args:
+      data:
+        A JSON dict
+      timestamp:
+        Gets set as the timestamp property of the new object
+
+    Returns:
+      A twitter.Trend object
+    '''
+    return Trend(name=data.get('name', None),
+                 query=data.get('query', None),
+                 timestamp=timestamp)
+
+class Url(object):
+  '''A class representing an URL contained in a tweet'''
+  def __init__(self,
+               url=None,
+               expanded_url=None):
+    self.url = url
+    self.expanded_url = expanded_url
+
+  @staticmethod
+  def NewFromJsonDict(data):
+    '''Create a new instance based on a JSON dict.
+
+    Args:
+      data:
+        A JSON dict, as converted from the JSON in the twitter API
+
+    Returns:
+      A twitter.Url instance
+    '''
+    return Url(url=data.get('url', None),
+               expanded_url=data.get('expanded_url', 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'] #...
+
+    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
+    consumer key and secret; and the oAuth key and secret:
+
+      >>> api = twitter.Api(consumer_key='twitter consumer key',
+                            consumer_secret='twitter consumer secret',
+                            access_token_key='the_key_given',
+                            access_token_secret='the_key_secret')
+
+    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,
+               consumer_key=None,
+               consumer_secret=None,
+               access_token_key=None,
+               access_token_secret=None,
+               input_encoding=None,
+               request_headers=None,
+               cache=DEFAULT_CACHE,
+               shortner=None,
+               base_url=None,
+               use_gzip_compression=False,
+               debugHTTP=False):
+    '''Instantiate a new twitter.Api object.
+
+    Args:
+      consumer_key:
+        Your Twitter user's consumer_key.
+      consumer_secret:
+        Your Twitter user's consumer_secret.
+      access_token_key:
+        The oAuth access token key value you retrieved
+        from running get_access_token.py.
+      access_token_secret:
+        The oAuth access token's secret, also retrieved
+        from the get_access_token.py run.
+      input_encoding:
+        The encoding used to encode input strings. [Optional]
+      request_header:
+        A dictionary of additional HTTP request headers. [Optional]
+      cache:
+        The cache instance to use. Defaults to DEFAULT_CACHE.
+        Use None to disable caching. [Optional]
+      shortner:
+        The shortner instance to use.  Defaults to None.
+        See shorten_url.py for an example shortner. [Optional]
+      base_url:
+        The base URL to use to contact the Twitter API.
+        Defaults to https://twitter.com. [Optional]
+      use_gzip_compression:
+        Set to True to tell enable gzip compression for any call
+        made to Twitter.  Defaults to False. [Optional]
+      debugHTTP:
+        Set to True to enable debug output from urllib2 when performing
+        any HTTP requests.  Defaults to False. [Optional]
+    '''
+    self.SetCache(cache)
+    self._urllib         = urllib2
+    self._cache_timeout  = Api.DEFAULT_CACHE_TIMEOUT
+    self._input_encoding = input_encoding
+    self._use_gzip       = use_gzip_compression
+    self._debugHTTP      = debugHTTP
+    self._oauth_consumer = None
+
+    self._InitializeRequestHeaders(request_headers)
+    self._InitializeUserAgent()
+    self._InitializeDefaultParameters()
+
+    if base_url is None:
+      self.base_url = 'http://api.t.sina.com.cn'
+    else:
+      self.base_url = base_url
+
+    if consumer_key is not None and (access_token_key is None or
+                                     access_token_secret is None):
+      print >> sys.stderr, 'Twitter now requires an oAuth Access Token for API calls.'
+      print >> sys.stderr, 'If your using this library from a command line utility, please'
+      print >> sys.stderr, 'run the the included get_access_token.py tool to generate one.'
+
+      raise WeiboError('Twitter requires oAuth Access Token for all API access')
+
+    self.SetCredentials(consumer_key, consumer_secret, access_token_key, access_token_secret)
+
+  def SetCredentials(self,
+                     consumer_key,
+                     consumer_secret,
+                     access_token_key=None,
+                     access_token_secret=None):
+    '''Set the consumer_key and consumer_secret for this instance
+
+    Args:
+      consumer_key:
+        The consumer_key of the twitter account.
+      consumer_secret:
+        The consumer_secret for the twitter account.
+      access_token_key:
+        The oAuth access token key value you retrieved
+        from running get_access_token.py.
+      access_token_secret:
+        The oAuth access token's secret, also retrieved
+        from the get_access_token.py run.
+    '''
+    self._consumer_key        = consumer_key
+    self._consumer_secret     = consumer_secret
+    self._access_token_key    = access_token_key
+    self._access_token_secret = access_token_secret
+    self._oauth_consumer      = None
+
+    if consumer_key is not None and consumer_secret is not None and \
+       access_token_key is not None and access_token_secret is not None:
+      self._signature_method_plaintext = oauth.SignatureMethod_PLAINTEXT()
+      self._signature_method_hmac_sha1 = oauth.SignatureMethod_HMAC_SHA1()
+
+      self._oauth_token    = oauth.Token(key=access_token_key, secret=access_token_secret)
+      self._oauth_consumer = oauth.Consumer(key=consumer_key, secret=consumer_secret)
+
+  def ClearCredentials(self):
+    '''Clear the any credentials for this instance
+    '''
+    self._consumer_key        = None
+    self._consumer_secret     = None
+    self._access_token_key    = None
+    self._access_token_secret = None
+    self._oauth_consumer      = None
+
+  def GetPublicTimeline(self,
+                        since_id=None,
+                        include_rts=None,
+                        include_entities=None):
+    '''Fetch the sequence of public twitter.Status message for all users.
+
+    Args:
+      since_id:
+        Returns results with an ID greater than (that is, more recent
+        than) the specified ID. There are limits to the number of
+        Tweets which can be accessed through the API. If the limit of
+        Tweets has occured since the since_id, the since_id will be
+        forced to the oldest ID available. [Optional]
+      include_rts:
+        If True, the timeline will contain native retweets (if they
+        exist) in addition to the standard stream of tweets. [Optional]
+      include_entities:
+        If True, each tweet will include a node called "entities,".
+        This node offers a variety of metadata about the tweet in a
+        discreet structure, including: user_mentions, urls, and
+        hashtags. [Optional]
+
+    Returns:
+      An sequence of twitter.Status instances, one for each message
+    '''
+    parameters = {}
+
+    if since_id:
+      parameters['since_id'] = since_id
+    if include_rts:
+      parameters['include_rts'] = 1
+    if include_entities:
+      parameters['include_entities'] = 1
+
+    url  = '%s/statuses/public_timeline.json' % self.base_url
+    json = self._FetchUrl(url,  parameters=parameters)
+    data = self._ParseAndCheckTwitter(json)
+    return [Status.NewFromJsonDict(x) for x in data]