xitiomet is sharing code with you

Bitbucket is a code hosting site. Unlimited public and private repositories. Free for small teams.

Don't show this again

xitiomet / python-twitter (fork of saiyr / python-twitter)

Mostly the same, but i added support for Mentions http://apiwiki.twitter.com/Twitter-REST-API-Met...

Clone this repository (size: 393.3 KB): HTTPS / SSH
hg clone https://bitbucket.org/xitiomet/python-twitter
hg clone ssh://hg@bitbucket.org/xitiomet/python-twitter

python-twitter / twitter.py

commit
82aae45f64f2
parent
a58f4a7ad991
branch
default

Added GetMentions to twitter.py

1
fc159c49c080
#!/usr/bin/python2.4
2
4805aee792f0
#
3
4805aee792f0
# Copyright 2007 Google Inc. All Rights Reserved.
4
fceb5d2374d2
#
5
fceb5d2374d2
# Licensed under the Apache License, Version 2.0 (the "License");
6
fceb5d2374d2
# you may not use this file except in compliance with the License.
7
fceb5d2374d2
# You may obtain a copy of the License at
8
fceb5d2374d2
#
9
fceb5d2374d2
#     http://www.apache.org/licenses/LICENSE-2.0
10
fceb5d2374d2
#
11
fceb5d2374d2
# Unless required by applicable law or agreed to in writing, software
12
fceb5d2374d2
# distributed under the License is distributed on an "AS IS" BASIS,
13
fceb5d2374d2
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
fceb5d2374d2
# See the License for the specific language governing permissions and
15
fceb5d2374d2
# limitations under the License.
16
4805aee792f0
17
4805aee792f0
'''A library that provides a python interface to the Twitter API'''
18
4805aee792f0
19
4805aee792f0
__author__ = 'dewitt@google.com'
20
8aaa14d8c799
__version__ = '0.6-devel'
21
4805aee792f0
22
4805aee792f0
23
f73c99cf9b51
import base64
24
3a4752d10bb7
import calendar
25
4805aee792f0
import os
26
3a4752d10bb7
import rfc822
27
4805aee792f0
import simplejson
28
4dfd36cb761d
import sys
29
4805aee792f0
import tempfile
30
81cef10d2991
import textwrap
31
4805aee792f0
import time
32
4805aee792f0
import urllib
33
4805aee792f0
import urllib2
34
4805aee792f0
import urlparse
35
0ef37898cd2b
36
a58f4a7ad991
try:
37
a58f4a7ad991
    from hashlib import md5
38
a58f4a7ad991
except ImportError:
39
a58f4a7ad991
    from md5 import md5
40
a58f4a7ad991
41
4805aee792f0
42
81cef10d2991
CHARACTER_LIMIT = 140
43
81cef10d2991
44
81cef10d2991
45
4805aee792f0
class TwitterError(Exception):
46
4805aee792f0
  '''Base class for Twitter errors'''
47
2367f0c7822c
  
48
2367f0c7822c
  @property
49
2367f0c7822c
  def message(self):
50
2367f0c7822c
    '''Returns the first argument used to construct this error.'''
51
2367f0c7822c
    return self.args[0]
52
4805aee792f0
53
4805aee792f0
54
4805aee792f0
class Status(object):
55
4805aee792f0
  '''A class representing the Status structure used by the twitter API.
56
4805aee792f0
57
4805aee792f0
  The Status structure exposes the following properties:
58
4805aee792f0
59
4805aee792f0
    status.created_at
60
17f566981b41
    status.created_at_in_seconds # read only
61
a1e65b8c9435
    status.favorited
62
1139636b672f
    status.in_reply_to_screen_name
63
1139636b672f
    status.in_reply_to_user_id
64
1139636b672f
    status.in_reply_to_status_id
65
1139636b672f
    status.truncated
66
1139636b672f
    status.source
67
4805aee792f0
    status.id
68
4805aee792f0
    status.text
69
17f566981b41
    status.relative_created_at # read only
70
4805aee792f0
    status.user
71
4805aee792f0
  '''
72
4805aee792f0
  def __init__(self,
73
4805aee792f0
               created_at=None,
74
a1e65b8c9435
               favorited=None,
75
4805aee792f0
               id=None,
76
4805aee792f0
               text=None,
77
17f566981b41
               user=None,
78
1139636b672f
               in_reply_to_screen_name=None,
79
1139636b672f
               in_reply_to_user_id=None,
80
1139636b672f
               in_reply_to_status_id=None,
81
1139636b672f
               truncated=None,
82
1139636b672f
               source=None,
83
17f566981b41
               now=None):
84
4805aee792f0
    '''An object to hold a Twitter status message.
85
4805aee792f0
86
4805aee792f0
    This class is normally instantiated by the twitter.Api class and
87
4805aee792f0
    returned in a sequence.
88
4805aee792f0
89
4805aee792f0
    Note: Dates are posted in the form "Sat Jan 27 04:17:38 +0000 2007"
90
17f566981b41
91
4805aee792f0
    Args:
92
4805aee792f0
      created_at: The time this status message was posted
93
a1e65b8c9435
      favorited: Whether this is a favorite of the authenticated user
94
4805aee792f0
      id: The unique id of this status message
95
4805aee792f0
      text: The text of this status message
96
4805aee792f0
      relative_created_at:
97
4805aee792f0
        A human readable string representing the posting time
98
4805aee792f0
      user:
99
4805aee792f0
        A twitter.User instance representing the person posting the message
100
17f566981b41
      now:
101
17f566981b41
        The current time, if the client choses to set it.  Defaults to the
102
17f566981b41
        wall clock time.
103
4805aee792f0
    '''
104
17f566981b41
    self.created_at = created_at
105
a1e65b8c9435
    self.favorited = favorited
106
4805aee792f0
    self.id = id
107
4805aee792f0
    self.text = text
108
4805aee792f0
    self.user = user
109
e565d3a31699
    self.now = now
110
1139636b672f
    self.in_reply_to_screen_name = in_reply_to_screen_name
111
1139636b672f
    self.in_reply_to_user_id = in_reply_to_user_id
112
1139636b672f
    self.in_reply_to_status_id = in_reply_to_status_id
113
1139636b672f
    self.truncated = truncated
114
1139636b672f
    self.source = source
115
4805aee792f0
116
4805aee792f0
  def GetCreatedAt(self):
117
4805aee792f0
    '''Get the time this status message was posted.
118
4805aee792f0
119
4805aee792f0
    Returns:
120
4805aee792f0
      The time this status message was posted
121
4805aee792f0
    '''
122
4805aee792f0
    return self._created_at
123
4805aee792f0
124
4805aee792f0
  def SetCreatedAt(self, created_at):
125
4805aee792f0
    '''Set the time this status message was posted.
126
4805aee792f0
127
4805aee792f0
    Args:
128
4805aee792f0
      created_at: The time this status message was created
129
4805aee792f0
    '''
130
4805aee792f0
    self._created_at = created_at
131
4805aee792f0
132
4805aee792f0
  created_at = property(GetCreatedAt, SetCreatedAt,
133
4805aee792f0
                        doc='The time this status message was posted.')
134
4805aee792f0
135
17f566981b41
  def GetCreatedAtInSeconds(self):
136
17f566981b41
    '''Get the time this status message was posted, in seconds since the epoch.
137
17f566981b41
138
17f566981b41
    Returns:
139
17f566981b41
      The time this status message was posted, in seconds since the epoch.
140
17f566981b41
    '''
141
3a4752d10bb7
    return calendar.timegm(rfc822.parsedate(self.created_at))
142
17f566981b41
143
17f566981b41
  created_at_in_seconds = property(GetCreatedAtInSeconds,
144
17f566981b41
                                   doc="The time this status message was "
145
17f566981b41
                                       "posted, in seconds since the epoch")
146
17f566981b41
147
a1e65b8c9435
  def GetFavorited(self):
148
a1e65b8c9435
    '''Get the favorited setting of this status message.
149
a1e65b8c9435
150
a1e65b8c9435
    Returns:
151
a1e65b8c9435
      True if this status message is favorited; False otherwise
152
a1e65b8c9435
    '''
153
a1e65b8c9435
    return self._favorited
154
a1e65b8c9435
155
a1e65b8c9435
  def SetFavorited(self, favorited):
156
a1e65b8c9435
    '''Set the favorited state of this status message.
157
a1e65b8c9435
158
a1e65b8c9435
    Args:
159
a1e65b8c9435
      favorited: boolean True/False favorited state of this status message
160
a1e65b8c9435
    '''
161
a1e65b8c9435
    self._favorited = favorited
162
a1e65b8c9435
163
a1e65b8c9435
  favorited = property(GetFavorited, SetFavorited,
164
a1e65b8c9435
                       doc='The favorited state of this status message.')
165
a1e65b8c9435
166
4805aee792f0
  def GetId(self):
167
4805aee792f0
    '''Get the unique id of this status message.
168
4805aee792f0
169
4805aee792f0
    Returns:
170
4805aee792f0
      The unique id of this status message
171
4805aee792f0
    '''
172
4805aee792f0
    return self._id
173
4805aee792f0
174
4805aee792f0
  def SetId(self, id):
175
4805aee792f0
    '''Set the unique id of this status message.
176
4805aee792f0
177
4805aee792f0
    Args:
178
4805aee792f0
      id: The unique id of this status message
179
4805aee792f0
    '''
180
4805aee792f0
    self._id = id
181
4805aee792f0
182
4805aee792f0
  id = property(GetId, SetId,
183
4805aee792f0
                doc='The unique id of this status message.')
184
4805aee792f0
185
1139636b672f
  def GetInReplyToScreenName(self):
186
1139636b672f
    return self._in_reply_to_screen_name
187
1139636b672f
188
1139636b672f
  def SetInReplyToScreenName(self, in_reply_to_screen_name):
189
1139636b672f
    self._in_reply_to_screen_name = in_reply_to_screen_name
190
1139636b672f
191
1139636b672f
  in_reply_to_screen_name = property(GetInReplyToScreenName, SetInReplyToScreenName,
192
1139636b672f
                doc='')
193
1139636b672f
194
1139636b672f
  def GetInReplyToUserId(self):
195
1139636b672f
    return self._in_reply_to_user_id
196
1139636b672f
197
1139636b672f
  def SetInReplyToUserId(self, in_reply_to_user_id):
198
1139636b672f
    self._in_reply_to_user_id = in_reply_to_user_id
199
1139636b672f
200
1139636b672f
  in_reply_to_user_id = property(GetInReplyToUserId, SetInReplyToUserId,
201
1139636b672f
                doc='')
202
1139636b672f
203
1139636b672f
  def GetInReplyToStatusId(self):
204
1139636b672f
    return self._in_reply_to_status_id
205
1139636b672f
206
1139636b672f
  def SetInReplyToStatusId(self, in_reply_to_status_id):
207
1139636b672f
    self._in_reply_to_status_id = in_reply_to_status_id
208
1139636b672f
209
1139636b672f
  in_reply_to_status_id = property(GetInReplyToStatusId, SetInReplyToStatusId,
210
1139636b672f
                doc='')
211
1139636b672f
212
1139636b672f
  def GetTruncated(self):
213
1139636b672f
    return self._truncated
214
1139636b672f
215
1139636b672f
  def SetTruncated(self, truncated):
216
1139636b672f
    self._truncated = truncated
217
1139636b672f
218
1139636b672f
  truncated = property(GetTruncated, SetTruncated,
219
1139636b672f
                doc='')
220
1139636b672f
221
1139636b672f
  def GetSource(self):
222
1139636b672f
    return self._source
223
1139636b672f
224
1139636b672f
  def SetSource(self, source):
225
1139636b672f
    self._source = source
226
1139636b672f
227
1139636b672f
  source = property(GetSource, SetSource,
228
1139636b672f
                doc='')
229
1139636b672f
230
4805aee792f0
  def GetText(self):
231
4805aee792f0
    '''Get the text of this status message.
232
4805aee792f0
233
4805aee792f0
    Returns:
234
4805aee792f0
      The text of this status message.
235
4805aee792f0
    '''
236
4805aee792f0
    return self._text
237
4805aee792f0
238
4805aee792f0
  def SetText(self, text):
239
4805aee792f0
    '''Set the text of this status message.
240
4805aee792f0
241
4805aee792f0
    Args:
242
4805aee792f0
      text: The text of this status message
243
4805aee792f0
    '''
244
4805aee792f0
    self._text = text
245
4805aee792f0
246
4805aee792f0
  text = property(GetText, SetText,
247
4805aee792f0
                  doc='The text of this status message')
248
4805aee792f0
249
4805aee792f0
  def GetRelativeCreatedAt(self):
250
4805aee792f0
    '''Get a human redable string representing the posting time
251
4805aee792f0
252
4805aee792f0
    Returns:
253
4805aee792f0
      A human readable string representing the posting time
254
4805aee792f0
    '''
255
3c401eb136ea
    fudge = 1.25
256
e565d3a31699
    delta  = int(self.now) - int(self.created_at_in_seconds)
257
4805aee792f0
258
3c401eb136ea
    if delta < (1 * fudge):
259
3c401eb136ea
      return 'about a second ago'
260
3c401eb136ea
    elif delta < (60 * (1/fudge)):
261
3c401eb136ea
      return 'about %d seconds ago' % (delta)
262
3c401eb136ea
    elif delta < (60 * fudge):
263
17f566981b41
      return 'about a minute ago'
264
3c401eb136ea
    elif delta < (60 * 60 * (1/fudge)):
265
3c401eb136ea
      return 'about %d minutes ago' % (delta / 60)
266
3c401eb136ea
    elif delta < (60 * 60 * fudge):
267
17f566981b41
      return 'about an hour ago'
268
3c401eb136ea
    elif delta < (60 * 60 * 24 * (1/fudge)):
269
3c401eb136ea
      return 'about %d hours ago' % (delta / (60 * 60))
270
3c401eb136ea
    elif delta < (60 * 60 * 24 * fudge):
271
3c401eb136ea
      return 'about a day ago'
272
17f566981b41
    else:
273
3c401eb136ea
      return 'about %d days ago' % (delta / (60 * 60 * 24))
274
4805aee792f0
275
3c401eb136ea
  relative_created_at = property(GetRelativeCreatedAt,
276
3c401eb136ea
                                 doc='Get a human readable string representing'
277
3c401eb136ea
                                     'the posting time')
278
dbe3b23bfd08
279
4805aee792f0
  def GetUser(self):
280
4805aee792f0
    '''Get a twitter.User reprenting the entity posting this status message.
281
4805aee792f0
282
4805aee792f0
    Returns:
283
4805aee792f0
      A twitter.User reprenting the entity posting this status message
284
4805aee792f0
    '''
285
4805aee792f0
    return self._user
286
4805aee792f0
287
4805aee792f0
  def SetUser(self, user):
288
4805aee792f0
    '''Set a twitter.User reprenting the entity posting this status message.
289
4805aee792f0
290
4805aee792f0
    Args:
291
4805aee792f0
      user: A twitter.User reprenting the entity posting this status message
292
4805aee792f0
    '''
293
4805aee792f0
    self._user = user
294
4805aee792f0
295
4805aee792f0
  user = property(GetUser, SetUser,
296
4805aee792f0
                  doc='A twitter.User reprenting the entity posting this '
297
4805aee792f0
                      'status message')
298
4805aee792f0
299
3c401eb136ea
  def GetNow(self):
300
3c401eb136ea
    '''Get the wallclock time for this status message.
301
3c401eb136ea
302
3c401eb136ea
    Used to calculate relative_created_at.  Defaults to the time
303
3c401eb136ea
    the object was instantiated.
304
dbe3b23bfd08
305
3c401eb136ea
    Returns:
306
3c401eb136ea
      Whatever the status instance believes the current time to be,
307
3c401eb136ea
      in seconds since the epoch.
308
3c401eb136ea
    '''
309
8218c3572da9
    if self._now is None:
310
c68ef9d563c3
      self._now = time.time()
311
3c401eb136ea
    return self._now
312
3c401eb136ea
313
3c401eb136ea
  def SetNow(self, now):
314
3c401eb136ea
    '''Set the wallclock time for this status message.
315
3c401eb136ea
316
3c401eb136ea
    Used to calculate relative_created_at.  Defaults to the time
317
3c401eb136ea
    the object was instantiated.
318
3c401eb136ea
319
3c401eb136ea
    Args:
320
3c401eb136ea
      now: The wallclock time for this instance.
321
3c401eb136ea
    '''
322
3c401eb136ea
    self._now = now
323
3c401eb136ea
324
3c401eb136ea
  now = property(GetNow, SetNow,
325
3c401eb136ea
                 doc='The wallclock time for this status instance.')
326
3c401eb136ea
327
dbe3b23bfd08
328
4805aee792f0
  def __ne__(self, other):
329
4805aee792f0
    return not self.__eq__(other)
330
4805aee792f0
331
4805aee792f0
  def __eq__(self, other):
332
4805aee792f0
    try:
333
4805aee792f0
      return other and \
334
4805aee792f0
             self.created_at == other.created_at and \
335
4805aee792f0
             self.id == other.id and \
336
4805aee792f0
             self.text == other.text and \
337
1139636b672f
             self.user == other.user and \
338
1139636b672f
             self.in_reply_to_screen_name == other.in_reply_to_screen_name and \
339
1139636b672f
             self.in_reply_to_user_id == other.in_reply_to_user_id and \
340
1139636b672f
             self.in_reply_to_status_id == other.in_reply_to_status_id and \
341
1139636b672f
             self.truncated == other.truncated and \
342
1139636b672f
             self.favorited == other.favorited and \
343
1139636b672f
             self.source == other.source
344
4805aee792f0
    except AttributeError:
345
4805aee792f0
      return False
346
17f566981b41
347
4805aee792f0
  def __str__(self):
348
4805aee792f0
    '''A string representation of this twitter.Status instance.
349
4805aee792f0
350
4805aee792f0
    The return value is the same as the JSON string representation.
351
4805aee792f0
352
4805aee792f0
    Returns:
353
17f566981b41
      A string representation of this twitter.Status instance.
354
4805aee792f0
    '''
355
4805aee792f0
    return self.AsJsonString()
356
4805aee792f0
357
4805aee792f0
  def AsJsonString(self):
358
4805aee792f0
    '''A JSON string representation of this twitter.Status instance.
359
4805aee792f0
360
4805aee792f0
    Returns:
361
4805aee792f0
      A JSON string representation of this twitter.Status instance
362
17f566981b41
   '''
363
4805aee792f0
    return simplejson.dumps(self.AsDict(), sort_keys=True)
364
17f566981b41
365
4805aee792f0
  def AsDict(self):
366
4805aee792f0
    '''A dict representation of this twitter.Status instance.
367
4805aee792f0
368
4805aee792f0
    The return value uses the same key names as the JSON representation.
369
4805aee792f0
370
4805aee792f0
    Return:
371
4805aee792f0
      A dict representing this twitter.Status instance
372
4805aee792f0
    '''
373
4805aee792f0
    data = {}
374
4805aee792f0
    if self.created_at:
375
4805aee792f0
      data['created_at'] = self.created_at
376
a1e65b8c9435
    if self.favorited:
377
a1e65b8c9435
      data['favorited'] = self.favorited
378
4805aee792f0
    if self.id:
379
4805aee792f0
      data['id'] = self.id
380
4805aee792f0
    if self.text:
381
4805aee792f0
      data['text'] = self.text
382
4805aee792f0
    if self.user:
383
4805aee792f0
      data['user'] = self.user.AsDict()
384
1139636b672f
    if self.in_reply_to_screen_name:
385
1139636b672f
      data['in_reply_to_screen_name'] = self.in_reply_to_screen_name
386
1139636b672f
    if self.in_reply_to_user_id:
387
1139636b672f
      data['in_reply_to_user_id'] = self.in_reply_to_user_id
388
1139636b672f
    if self.in_reply_to_status_id:
389
1139636b672f
      data['in_reply_to_status_id'] = self.in_reply_to_status_id
390
1139636b672f
    if self.truncated is not None:
391
1139636b672f
      data['truncated'] = self.truncated
392
1139636b672f
    if self.favorited is not None:
393
1139636b672f
      data['favorited'] = self.favorited
394
1139636b672f
    if self.source:
395
1139636b672f
      data['source'] = self.source
396
4805aee792f0
    return data
397
4805aee792f0
398
4805aee792f0
  @staticmethod
399
4805aee792f0
  def NewFromJsonDict(data):
400
4805aee792f0
    '''Create a new instance based on a JSON dict.
401
4805aee792f0
402
4805aee792f0
    Args:
403
4805aee792f0
      data: A JSON dict, as converted from the JSON in the twitter API
404
4805aee792f0
    Returns:
405
4805aee792f0
      A twitter.Status instance
406
4805aee792f0
    '''
407
4805aee792f0
    if 'user' in data:
408
4805aee792f0
      user = User.NewFromJsonDict(data['user'])
409
4805aee792f0
    else:
410
4805aee792f0
      user = None
411
4805aee792f0
    return Status(created_at=data.get('created_at', None),
412
a1e65b8c9435
                  favorited=data.get('favorited', None),
413
4805aee792f0
                  id=data.get('id', None),
414
4805aee792f0
                  text=data.get('text', None),
415
1139636b672f
                  in_reply_to_screen_name=data.get('in_reply_to_screen_name', None),
416
1139636b672f
                  in_reply_to_user_id=data.get('in_reply_to_user_id', None),
417
1139636b672f
                  in_reply_to_status_id=data.get('in_reply_to_status_id', None),
418
1139636b672f
                  truncated=data.get('truncated', None),
419
1139636b672f
                  source=data.get('source', None),
420
4805aee792f0
                  user=user)
421
4805aee792f0
422
4805aee792f0
423
4805aee792f0
class User(object):
424
4805aee792f0
  '''A class representing the User structure used by the twitter API.
425
4805aee792f0
426
4805aee792f0
  The User structure exposes the following properties:
427
4805aee792f0
428
4805aee792f0
    user.id
429
4805aee792f0
    user.name
430
4805aee792f0
    user.screen_name
431
4805aee792f0
    user.location
432
4805aee792f0
    user.description
433
4805aee792f0
    user.profile_image_url
434
1139636b672f
    user.profile_background_tile
435
1139636b672f
    user.profile_background_image_url
436
1139636b672f
    user.profile_sidebar_fill_color
437
1139636b672f
    user.profile_background_color
438
1139636b672f
    user.profile_link_color
439
1139636b672f
    user.profile_text_color
440
1139636b672f
    user.protected
441
1139636b672f
    user.utc_offset
442
1139636b672f
    user.time_zone
443
4805aee792f0
    user.url
444
4805aee792f0
    user.status
445
1139636b672f
    user.statuses_count
446
1139636b672f
    user.followers_count
447
1139636b672f
    user.friends_count
448
1139636b672f
    user.favourites_count
449
4805aee792f0
  '''
450
4805aee792f0
  def __init__(self,
451
4805aee792f0
               id=None,
452
4805aee792f0
               name=None,
453
4805aee792f0
               screen_name=None,
454
4805aee792f0
               location=None,
455
4805aee792f0
               description=None,
456
4805aee792f0
               profile_image_url=None,
457
1139636b672f
               profile_background_tile=None,
458
1139636b672f
               profile_background_image_url=None,
459
1139636b672f
               profile_sidebar_fill_color=None,
460
1139636b672f
               profile_background_color=None,
461
1139636b672f
               profile_link_color=None,
462
1139636b672f
               profile_text_color=None,
463
1139636b672f
               protected=None,
464
1139636b672f
               utc_offset=None,
465
1139636b672f
               time_zone=None,
466
1139636b672f
               followers_count=None,
467
1139636b672f
               friends_count=None,
468
1139636b672f
               statuses_count=None,
469
1139636b672f
               favourites_count=None,
470
4805aee792f0
               url=None,
471
4805aee792f0
               status=None):
472
4805aee792f0
    self.id = id
473
4805aee792f0
    self.name = name
474
4805aee792f0
    self.screen_name = screen_name
475
4805aee792f0
    self.location = location
476
4805aee792f0
    self.description = description
477
4805aee792f0
    self.profile_image_url = profile_image_url
478
1139636b672f
    self.profile_background_tile = profile_background_tile
479
1139636b672f
    self.profile_background_image_url = profile_background_image_url
480
1139636b672f
    self.profile_sidebar_fill_color = profile_sidebar_fill_color
481
1139636b672f
    self.profile_background_color = profile_background_color
482
1139636b672f
    self.profile_link_color = profile_link_color
483
1139636b672f
    self.profile_text_color = profile_text_color
484
1139636b672f
    self.protected = protected
485
1139636b672f
    self.utc_offset = utc_offset
486
1139636b672f
    self.time_zone = time_zone
487
1139636b672f
    self.followers_count = followers_count
488
1139636b672f
    self.friends_count = friends_count
489
1139636b672f
    self.statuses_count = statuses_count
490
1139636b672f
    self.favourites_count = favourites_count
491
4805aee792f0
    self.url = url
492
4805aee792f0
    self.status = status
493
4805aee792f0
494
4805aee792f0
495
4805aee792f0
  def GetId(self):
496
4805aee792f0
    '''Get the unique id of this user.
497
4805aee792f0
498
4805aee792f0
    Returns:
499
4805aee792f0
      The unique id of this user
500
4805aee792f0
    '''
501
4805aee792f0
    return self._id
502
4805aee792f0
503
4805aee792f0
  def SetId(self, id):
504
4805aee792f0
    '''Set the unique id of this user.
505
4805aee792f0
506
4805aee792f0
    Args:
507
4805aee792f0
      id: The unique id of this user.
508
4805aee792f0
    '''
509
4805aee792f0
    self._id = id
510
4805aee792f0
511
4805aee792f0
  id = property(GetId, SetId,
512
4805aee792f0
                doc='The unique id of this user.')
513
4805aee792f0
514
4805aee792f0
  def GetName(self):
515
4805aee792f0
    '''Get the real name of this user.
516
4805aee792f0
517
4805aee792f0
    Returns:
518
4805aee792f0
      The real name of this user
519
4805aee792f0
    '''
520
4805aee792f0
    return self._name
521
4805aee792f0
522
4805aee792f0
  def SetName(self, name):
523
4805aee792f0
    '''Set the real name of this user.
524
4805aee792f0
525
4805aee792f0
    Args:
526
4805aee792f0
      name: The real name of this user
527
4805aee792f0
    '''
528
4805aee792f0
    self._name = name
529
4805aee792f0
530
4805aee792f0
  name = property(GetName, SetName,
531
4805aee792f0
                  doc='The real name of this user.')
532
4805aee792f0
533
4805aee792f0
  def GetScreenName(self):
534
4805aee792f0
    '''Get the short username of this user.
535
4805aee792f0
536
4805aee792f0
    Returns:
537
4805aee792f0
      The short username of this user
538
4805aee792f0
    '''
539
4805aee792f0
    return self._screen_name
540
4805aee792f0
541
4805aee792f0
  def SetScreenName(self, screen_name):
542
4805aee792f0
    '''Set the short username of this user.
543
4805aee792f0
544
4805aee792f0
    Args:
545
4805aee792f0
      screen_name: the short username of this user
546
4805aee792f0
    '''
547
4805aee792f0
    self._screen_name = screen_name
548
4805aee792f0
549
4805aee792f0
  screen_name = property(GetScreenName, SetScreenName,
550
4805aee792f0
                         doc='The short username of this user.')
551
4805aee792f0
552
4805aee792f0
  def GetLocation(self):
553
4805aee792f0
    '''Get the geographic location of this user.
554
4805aee792f0
555
4805aee792f0
    Returns:
556
4805aee792f0
      The geographic location of this user
557
4805aee792f0
    '''
558
4805aee792f0
    return self._location
559
4805aee792f0
560
4805aee792f0
  def SetLocation(self, location):
561
4805aee792f0
    '''Set the geographic location of this user.
562
4805aee792f0
563
4805aee792f0
    Args:
564
4805aee792f0
      location: The geographic location of this user
565
4805aee792f0
    '''
566
4805aee792f0
    self._location = location
567
4805aee792f0
568
4805aee792f0
  location = property(GetLocation, SetLocation,
569
4805aee792f0
                      doc='The geographic location of this user.')
570
17f566981b41
571
4805aee792f0
  def GetDescription(self):
572
4805aee792f0
    '''Get the short text description of this user.
573
4805aee792f0
574
4805aee792f0
    Returns:
575
4805aee792f0
      The short text description of this user
576
4805aee792f0
    '''
577
4805aee792f0
    return self._description
578
4805aee792f0
579
4805aee792f0
  def SetDescription(self, description):
580
4805aee792f0
    '''Set the short text description of this user.
581
4805aee792f0
582
4805aee792f0
    Args:
583
4805aee792f0
      description: The short text description of this user
584
4805aee792f0
    '''
585
4805aee792f0
    self._description = description
586
4805aee792f0
587
4805aee792f0
  description = property(GetDescription, SetDescription,
588
4805aee792f0
                         doc='The short text description of this user.')
589
17f566981b41
590
4805aee792f0
  def GetUrl(self):
591
4805aee792f0
    '''Get the homepage url of this user.
592
4805aee792f0
593
4805aee792f0
    Returns:
594
4805aee792f0
      The homepage url of this user
595
4805aee792f0
    '''
596
4805aee792f0
    return self._url
597
4805aee792f0
598
4805aee792f0
  def SetUrl(self, url):
599
4805aee792f0
    '''Set the homepage url of this user.
600
4805aee792f0
601
4805aee792f0
    Args:
602
4805aee792f0
      url: The homepage url of this user
603
4805aee792f0
    '''
604
4805aee792f0
    self._url = url
605
4805aee792f0
606
4805aee792f0
  url = property(GetUrl, SetUrl,
607
4805aee792f0
                 doc='The homepage url of this user.')
608
4805aee792f0
609
4805aee792f0
  def GetProfileImageUrl(self):
610
4805aee792f0
    '''Get the url of the thumbnail of this user.
611
4805aee792f0
612
4805aee792f0
    Returns:
613
4805aee792f0
      The url of the thumbnail of this user
614
4805aee792f0
    '''
615
4805aee792f0
    return self._profile_image_url
616
4805aee792f0
617
4805aee792f0
  def SetProfileImageUrl(self, profile_image_url):
618
4805aee792f0
    '''Set the url of the thumbnail of this user.
619
4805aee792f0
620
4805aee792f0
    Args:
621
4805aee792f0
      profile_image_url: The url of the thumbnail of this user
622
4805aee792f0
    '''
623
4805aee792f0
    self._profile_image_url = profile_image_url
624
4805aee792f0
625
4805aee792f0
  profile_image_url= property(GetProfileImageUrl, SetProfileImageUrl,
626
4805aee792f0
                              doc='The url of the thumbnail of this user.')
627
4805aee792f0
628
1139636b672f
  def GetProfileBackgroundTile(self):
629
1139636b672f
    '''Boolean for whether to tile the profile background image.
630
1139636b672f
631
1139636b672f
    Returns:
632
1139636b672f
      True if the background is to be tiled, False if not, None if unset.
633
1139636b672f
    '''
634
1139636b672f
    return self._profile_background_tile
635
1139636b672f
636
1139636b672f
  def SetProfileBackgroundTile(self, profile_background_tile):
637
1139636b672f
    '''Set the boolean flag for whether to tile the profile background image.
638
1139636b672f
639
1139636b672f
    Args:
640
1139636b672f
      profile_background_tile: Boolean flag for whether to tile or not.
641
1139636b672f
    '''
642
1139636b672f
    self._profile_background_tile = profile_background_tile
643
1139636b672f
644
1139636b672f
  profile_background_tile = property(GetProfileBackgroundTile, SetProfileBackgroundTile,
645
1139636b672f
                                     doc='Boolean for whether to tile the background image.')
646
1139636b672f
647
1139636b672f
  def GetProfileBackgroundImageUrl(self):
648
1139636b672f
    return self._profile_background_image_url
649
1139636b672f
650
1139636b672f
  def SetProfileBackgroundImageUrl(self, profile_background_image_url):
651
1139636b672f
    self._profile_background_image_url = profile_background_image_url
652
1139636b672f
653
1139636b672f
  profile_background_image_url = property(GetProfileBackgroundImageUrl, SetProfileBackgroundImageUrl,
654
1139636b672f
                                          doc='The url of the profile background of this user.')
655
1139636b672f
656
1139636b672f
  def GetProfileSidebarFillColor(self):
657
1139636b672f
    return self._profile_sidebar_fill_color
658
1139636b672f
659
1139636b672f
  def SetProfileSidebarFillColor(self, profile_sidebar_fill_color):
660
1139636b672f
    self._profile_sidebar_fill_color = profile_sidebar_fill_color
661
1139636b672f
662
1139636b672f
  profile_sidebar_fill_color = property(GetProfileSidebarFillColor, SetProfileSidebarFillColor)
663
1139636b672f
664
1139636b672f
  def GetProfileBackgroundColor(self):
665
1139636b672f
    return self._profile_background_color
666
1139636b672f
667
1139636b672f
  def SetProfileBackgroundColor(self, profile_background_color):
668
1139636b672f
    self._profile_background_color = profile_background_color
669
1139636b672f
670
1139636b672f
  profile_background_color = property(GetProfileBackgroundColor, SetProfileBackgroundColor)
671
1139636b672f
672
1139636b672f
  def GetProfileLinkColor(self):
673
1139636b672f
    return self._profile_link_color
674
1139636b672f
675
1139636b672f
  def SetProfileLinkColor(self, profile_link_color):
676
1139636b672f
    self._profile_link_color = profile_link_color
677
1139636b672f
678
1139636b672f
  profile_link_color = property(GetProfileLinkColor, SetProfileLinkColor)
679
1139636b672f
680
1139636b672f
  def GetProfileTextColor(self):
681
1139636b672f
    return self._profile_text_color
682
1139636b672f
683
1139636b672f
  def SetProfileTextColor(self, profile_text_color):
684
1139636b672f
    self._profile_text_color = profile_text_color
685
1139636b672f
686
1139636b672f
  profile_text_color = property(GetProfileTextColor, SetProfileTextColor)
687
1139636b672f
688
1139636b672f
  def GetProtected(self):
689
1139636b672f
    return self._protected
690
1139636b672f
691
1139636b672f
  def SetProtected(self, protected):
692
1139636b672f
    self._protected = protected
693
1139636b672f
694
1139636b672f
  protected = property(GetProtected, SetProtected)
695
1139636b672f
696
1139636b672f
  def GetUtcOffset(self):
697
1139636b672f
    return self._utc_offset
698
1139636b672f
699
1139636b672f
  def SetUtcOffset(self, utc_offset):
700
1139636b672f
    self._utc_offset = utc_offset
701
1139636b672f
702
1139636b672f
  utc_offset = property(GetUtcOffset, SetUtcOffset)
703
1139636b672f
704
1139636b672f
  def GetTimeZone(self):
705
1139636b672f
    '''Returns the current time zone string for the user.
706
1139636b672f
707
1139636b672f
    Returns:
708
1139636b672f
      The descriptive time zone string for the user.
709
1139636b672f
    '''
710
1139636b672f
    return self._time_zone
711
1139636b672f
712
1139636b672f
  def SetTimeZone(self, time_zone):
713
1139636b672f
    '''Sets the user's time zone string.
714
1139636b672f
715
1139636b672f
    Args:
716
1139636b672f
      time_zone: The descriptive time zone to assign for the user.
717
1139636b672f
    '''
718
1139636b672f
    self._time_zone = time_zone
719
1139636b672f
720
1139636b672f
  time_zone = property(GetTimeZone, SetTimeZone)
721
1139636b672f
722
4805aee792f0
  def GetStatus(self):
723
4805aee792f0
    '''Get the latest twitter.Status of this user.
724
4805aee792f0
725
4805aee792f0
    Returns:
726
4805aee792f0
      The latest twitter.Status of this user
727
4805aee792f0
    '''
728
4805aee792f0
    return self._status
729
4805aee792f0
730
4805aee792f0
  def SetStatus(self, status):
731
4805aee792f0
    '''Set the latest twitter.Status of this user.
732
4805aee792f0
733
4805aee792f0
    Args:
734
4805aee792f0
      status: The latest twitter.Status of this user
735
4805aee792f0
    '''
736
4805aee792f0
    self._status = status
737
17f566981b41
738
4805aee792f0
  status = property(GetStatus, SetStatus,
739
4805aee792f0
                  doc='The latest twitter.Status of this user.')
740
4805aee792f0
741
1139636b672f
  def GetFriendsCount(self):
742
1139636b672f
    '''Get the friend count for this user.
743
1139636b672f
    
744
1139636b672f
    Returns:
745
1139636b672f
      The number of users this user has befriended.
746
1139636b672f
    '''
747
1139636b672f
    return self._friends_count
748
1139636b672f
749
1139636b672f
  def SetFriendsCount(self, count):
750
1139636b672f
    '''Set the friend count for this user.
751
1139636b672f
752
1139636b672f
    Args:
753
1139636b672f
      count: The number of users this user has befriended.
754
1139636b672f
    '''
755
1139636b672f
    self._friends_count = count
756
1139636b672f
757
1139636b672f
  friends_count = property(GetFriendsCount, SetFriendsCount,
758
1139636b672f
                  doc='The number of friends for this user.')
759
1139636b672f
760
1139636b672f
  def GetFollowersCount(self):
761
1139636b672f
    '''Get the follower count for this user.
762
1139636b672f
    
763
1139636b672f
    Returns:
764
1139636b672f
      The number of users following this user.
765
1139636b672f
    '''
766
1139636b672f
    return self._followers_count
767
1139636b672f
768
1139636b672f
  def SetFollowersCount(self, count):
769
1139636b672f
    '''Set the follower count for this user.
770
1139636b672f
771
1139636b672f
    Args:
772
1139636b672f
      count: The number of users following this user.
773
1139636b672f
    '''
774
1139636b672f
    self._followers_count = count
775
1139636b672f
776
1139636b672f
  followers_count = property(GetFollowersCount, SetFollowersCount,
777
1139636b672f
                  doc='The number of users following this user.')
778
1139636b672f
779
1139636b672f
  def GetStatusesCount(self):
780
1139636b672f
    '''Get the number of status updates for this user.
781
1139636b672f
    
782
1139636b672f
    Returns:
783
1139636b672f
      The number of status updates for this user.
784
1139636b672f
    '''
785
1139636b672f
    return self._statuses_count
786
1139636b672f
787
1139636b672f
  def SetStatusesCount(self, count):
788
1139636b672f
    '''Set the status update count for this user.
789
1139636b672f
790
1139636b672f
    Args:
791
1139636b672f
      count: The number of updates for this user.
792
1139636b672f
    '''
793
1139636b672f
    self._statuses_count = count
794
1139636b672f
795
1139636b672f
  statuses_count = property(GetStatusesCount, SetStatusesCount,
796
1139636b672f
                  doc='The number of updates for this user.')
797
1139636b672f
798
1139636b672f
  def GetFavouritesCount(self):
799
1139636b672f
    '''Get the number of favourites for this user.
800
1139636b672f
    
801
1139636b672f
    Returns:
802
1139636b672f
      The number of favourites for this user.
803
1139636b672f
    '''
804
1139636b672f
    return self._favourites_count
805
1139636b672f
806
1139636b672f
  def SetFavouritesCount(self, count):
807
1139636b672f
    '''Set the favourite count for this user.
808
1139636b672f
809
1139636b672f
    Args:
810
1139636b672f
      count: The number of favourites for this user.
811
1139636b672f
    '''
812
1139636b672f
    self._favourites_count = count
813
1139636b672f
814
1139636b672f
  favourites_count = property(GetFavouritesCount, SetFavouritesCount,
815
1139636b672f
                  doc='The number of favourites for this user.')
816
1139636b672f
817
4805aee792f0
  def __ne__(self, other):
818
4805aee792f0
    return not self.__eq__(other)
819
17f566981b41
820
4805aee792f0
  def __eq__(self, other):
821
4805aee792f0
    try:
822
4805aee792f0
      return other and \
823
4805aee792f0
             self.id == other.id and \
824
4805aee792f0
             self.name == other.name and \
825
4805aee792f0
             self.screen_name == other.screen_name and \
826
4805aee792f0
             self.location == other.location and \
827
4805aee792f0
             self.description == other.description and \
828
4805aee792f0
             self.profile_image_url == other.profile_image_url and \
829
1139636b672f
             self.profile_background_tile == other.profile_background_tile and \
830
1139636b672f
             self.profile_background_image_url == other.profile_background_image_url and \
831
1139636b672f
             self.profile_sidebar_fill_color == other.profile_sidebar_fill_color and \
832
1139636b672f
             self.profile_background_color == other.profile_background_color and \
833
1139636b672f
             self.profile_link_color == other.profile_link_color and \
834
1139636b672f
             self.profile_text_color == other.profile_text_color and \
835
1139636b672f
             self.protected == other.protected and \
836
1139636b672f
             self.utc_offset == other.utc_offset and \
837
1139636b672f
             self.time_zone == other.time_zone and \
838
4805aee792f0
             self.url == other.url and \
839
1139636b672f
             self.statuses_count == other.statuses_count and \
840
1139636b672f
             self.followers_count == other.followers_count and \
841
1139636b672f
             self.favourites_count == other.favourites_count and \
842
1139636b672f
             self.friends_count == other.friends_count and \
843
4805aee792f0
             self.status == other.status
844
4805aee792f0
    except AttributeError:
845
4805aee792f0
      return False
846
17f566981b41
847
4805aee792f0
  def __str__(self):
848
4805aee792f0
    '''A string representation of this twitter.User instance.
849
4805aee792f0
850
4805aee792f0
    The return value is the same as the JSON string representation.
851
4805aee792f0
852
4805aee792f0
    Returns:
853
17f566981b41
      A string representation of this twitter.User instance.
854
4805aee792f0
    '''
855
4805aee792f0
    return self.AsJsonString()
856
4805aee792f0
857
4805aee792f0
  def AsJsonString(self):
858
4805aee792f0
    '''A JSON string representation of this twitter.User instance.
859
4805aee792f0
860
4805aee792f0
    Returns:
861
4805aee792f0
      A JSON string representation of this twitter.User instance
862
17f566981b41
   '''
863
4805aee792f0
    return simplejson.dumps(self.AsDict(), sort_keys=True)
864
4805aee792f0
865
4805aee792f0
  def AsDict(self):
866
4805aee792f0
    '''A dict representation of this twitter.User instance.
867
4805aee792f0
868
4805aee792f0
    The return value uses the same key names as the JSON representation.
869
4805aee792f0
870
4805aee792f0
    Return:
871
4805aee792f0
      A dict representing this twitter.User instance
872
4805aee792f0
    '''
873
4805aee792f0
    data = {}
874
4805aee792f0
    if self.id:
875
4805aee792f0
      data['id'] = self.id
876
4805aee792f0
    if self.name:
877
4805aee792f0
      data['name'] = self.name
878
4805aee792f0
    if self.screen_name:
879
4805aee792f0
      data['screen_name'] = self.screen_name
880
4805aee792f0
    if self.location:
881
4805aee792f0
      data['location'] = self.location
882
4805aee792f0
    if self.description:
883
4805aee792f0
      data['description'] = self.description
884
4805aee792f0
    if self.profile_image_url:
885
4805aee792f0
      data['profile_image_url'] = self.profile_image_url
886
1139636b672f
    if self.profile_background_tile is not None:
887
1139636b672f
      data['profile_background_tile'] = self.profile_background_tile
888
1139636b672f
    if self.profile_background_image_url:
889
1139636b672f
      data['profile_sidebar_fill_color'] = self.profile_background_image_url
890
1139636b672f
    if self.profile_background_color:
891
1139636b672f
      data['profile_background_color'] = self.profile_background_color
892
1139636b672f
    if self.profile_link_color:
893
1139636b672f
      data['profile_link_color'] = self.profile_link_color
894
1139636b672f
    if self.profile_text_color:
895
1139636b672f
      data['profile_text_color'] = self.profile_text_color
896
1139636b672f
    if self.protected is not None:
897
1139636b672f
      data['protected'] = self.protected
898
1139636b672f
    if self.utc_offset:
899
1139636b672f
      data['utc_offset'] = self.utc_offset
900
1139636b672f
    if self.time_zone:
901
1139636b672f
      data['time_zone'] = self.time_zone
902
4805aee792f0
    if self.url:
903
4805aee792f0
      data['url'] = self.url
904
4805aee792f0
    if self.status:
905
4805aee792f0
      data['status'] = self.status.AsDict()
906
1139636b672f
    if self.friends_count:
907
1139636b672f
      data['friends_count'] = self.friends_count
908
1139636b672f
    if self.followers_count:
909
1139636b672f
      data['followers_count'] = self.followers_count
910
1139636b672f
    if self.statuses_count:
911
1139636b672f
      data['statuses_count'] = self.statuses_count
912
1139636b672f
    if self.favourites_count:
913
1139636b672f
      data['favourites_count'] = self.favourites_count
914
4805aee792f0
    return data
915
4805aee792f0
916
4805aee792f0
  @staticmethod
917
4805aee792f0
  def NewFromJsonDict(data):
918
4805aee792f0
    '''Create a new instance based on a JSON dict.
919
4805aee792f0
920
4805aee792f0
    Args:
921
4805aee792f0
      data: A JSON dict, as converted from the JSON in the twitter API
922
4805aee792f0
    Returns:
923
4805aee792f0
      A twitter.User instance
924
4805aee792f0
    '''
925
4805aee792f0
    if 'status' in data:
926
4805aee792f0
      status = Status.NewFromJsonDict(data['status'])
927
4805aee792f0
    else:
928
4805aee792f0
      status = None
929
4805aee792f0
    return User(id=data.get('id', None),
930
4805aee792f0
                name=data.get('name', None),
931
4805aee792f0
                screen_name=data.get('screen_name', None),
932
4805aee792f0
                location=data.get('location', None),
933
4805aee792f0
                description=data.get('description', None),
934
1139636b672f
                statuses_count=data.get('statuses_count', None),
935
1139636b672f
                followers_count=data.get('followers_count', None),
936
1139636b672f
                favourites_count=data.get('favourites_count', None),
937
1139636b672f
                friends_count=data.get('friends_count', None),
938
4805aee792f0
                profile_image_url=data.get('profile_image_url', None),
939
1139636b672f
                profile_background_tile = data.get('profile_background_tile', None),
940
1139636b672f
                profile_background_image_url = data.get('profile_background_image_url', None),
941
1139636b672f
                profile_sidebar_fill_color = data.get('profile_sidebar_fill_color', None),
942
1139636b672f
                profile_background_color = data.get('profile_background_color', None),
943
1139636b672f
                profile_link_color = data.get('profile_link_color', None),
944
1139636b672f
                profile_text_color = data.get('profile_text_color', None),
945
1139636b672f
                protected = data.get('protected', None),
946
1139636b672f
                utc_offset = data.get('utc_offset', None),
947
1139636b672f
                time_zone = data.get('time_zone', None),
948
4805aee792f0
                url=data.get('url', None),
949
4805aee792f0
                status=status)
950
4805aee792f0
951
c42880b017af
class DirectMessage(object):
952
950d53433f5b
  '''A class representing the DirectMessage structure used by the twitter API.
953
950d53433f5b
954
950d53433f5b
  The DirectMessage structure exposes the following properties:
955
950d53433f5b
956
950d53433f5b
    direct_message.id
957
950d53433f5b
    direct_message.created_at
958
950d53433f5b
    direct_message.created_at_in_seconds # read only
959
950d53433f5b
    direct_message.sender_id
960
950d53433f5b
    direct_message.sender_screen_name
961
950d53433f5b
    direct_message.recipient_id
962
950d53433f5b
    direct_message.recipient_screen_name
963
950d53433f5b
    direct_message.text
964
950d53433f5b
  '''
965
c42880b017af
966
c42880b017af
  def __init__(self,
967
950d53433f5b
               id=None,
968
c42880b017af
               created_at=None,
969
950d53433f5b
               sender_id=None,
970
950d53433f5b
               sender_screen_name=None,
971
c42880b017af
               recipient_id=None,
972
950d53433f5b
               recipient_screen_name=None,
973
950d53433f5b
               text=None):
974
950d53433f5b
    '''An object to hold a Twitter direct message.
975
950d53433f5b
976
950d53433f5b
    This class is normally instantiated by the twitter.Api class and
977
950d53433f5b
    returned in a sequence.
978
950d53433f5b
979
950d53433f5b
    Note: Dates are posted in the form "Sat Jan 27 04:17:38 +0000 2007"
980
950d53433f5b
981
950d53433f5b
    Args:
982
950d53433f5b
      id: The unique id of this direct message
983
950d53433f5b
      created_at: The time this direct message was posted
984
950d53433f5b
      sender_id: The id of the twitter user that sent this message
985
950d53433f5b
      sender_screen_name: The name of the twitter user that sent this message
986
950d53433f5b
      recipient_id: The id of the twitter that received this message
987
950d53433f5b
      recipient_screen_name: The name of the twitter that received this message
988
950d53433f5b
      text: The text of this direct message
989
950d53433f5b
    '''
990
950d53433f5b
    self.id = id
991
c42880b017af
    self.created_at = created_at
992
950d53433f5b
    self.sender_id = sender_id
993
950d53433f5b
    self.sender_screen_name = sender_screen_name
994
c42880b017af
    self.recipient_id = recipient_id
995
950d53433f5b
    self.recipient_screen_name = recipient_screen_name
996
c42880b017af
    self.text = text
997
950d53433f5b
998
950d53433f5b
  def GetId(self):
999
950d53433f5b
    '''Get the unique id of this direct message.
1000
950d53433f5b
1001
950d53433f5b
    Returns:
1002
950d53433f5b
      The unique id of this direct message
1003
950d53433f5b
    '''
1004
950d53433f5b
    return self._id
1005
950d53433f5b
1006
950d53433f5b
  def SetId(self, id):
1007
950d53433f5b
    '''Set the unique id of this direct message.
1008
950d53433f5b
1009
950d53433f5b
    Args:
1010
950d53433f5b
      id: The unique id of this direct message
1011
950d53433f5b
    '''
1012
950d53433f5b
    self._id = id
1013
950d53433f5b
1014
950d53433f5b
  id = property(GetId, SetId,
1015
950d53433f5b
                doc='The unique id of this direct message.')
1016
950d53433f5b
1017
950d53433f5b
  def GetCreatedAt(self):
1018
950d53433f5b
    '''Get the time this direct message was posted.
1019
950d53433f5b
1020
950d53433f5b
    Returns:
1021
950d53433f5b
      The time this direct message was posted
1022
950d53433f5b
    '''
1023
950d53433f5b
    return self._created_at
1024
950d53433f5b
1025
950d53433f5b
  def SetCreatedAt(self, created_at):
1026
950d53433f5b
    '''Set the time this direct message was posted.
1027
950d53433f5b
1028
950d53433f5b
    Args:
1029
950d53433f5b
      created_at: The time this direct message was created
1030
950d53433f5b
    '''
1031
950d53433f5b
    self._created_at = created_at
1032
950d53433f5b
1033
950d53433f5b
  created_at = property(GetCreatedAt, SetCreatedAt,
1034
950d53433f5b
                        doc='The time this direct message was posted.')
1035
950d53433f5b
1036
950d53433f5b
  def GetCreatedAtInSeconds(self):
1037
950d53433f5b
    '''Get the time this direct message was posted, in seconds since the epoch.
1038
950d53433f5b
1039
950d53433f5b
    Returns:
1040
950d53433f5b
      The time this direct message was posted, in seconds since the epoch.
1041
950d53433f5b
    '''
1042
3a4752d10bb7
    return calendar.timegm(rfc822.parsedate(self.created_at))
1043
950d53433f5b
1044
950d53433f5b
  created_at_in_seconds = property(GetCreatedAtInSeconds,
1045
950d53433f5b
                                   doc="The time this direct message was "
1046
950d53433f5b
                                       "posted, in seconds since the epoch")
1047
950d53433f5b
1048
950d53433f5b
  def GetSenderId(self):
1049
950d53433f5b
    '''Get the unique sender id of this direct message.
1050
950d53433f5b
1051
950d53433f5b
    Returns:
1052
950d53433f5b
      The unique sender id of this direct message
1053
950d53433f5b
    '''
1054
950d53433f5b
    return self._sender_id
1055
950d53433f5b
1056
950d53433f5b
  def SetSenderId(self, sender_id):
1057
950d53433f5b
    '''Set the unique sender id of this direct message.
1058
950d53433f5b
1059
950d53433f5b
    Args:
1060
950d53433f5b
      sender id: The unique sender id of this direct message
1061
950d53433f5b
    '''
1062
950d53433f5b
    self._sender_id = sender_id
1063
950d53433f5b
1064
950d53433f5b
  sender_id = property(GetSenderId, SetSenderId,
1065
950d53433f5b
                doc='The unique sender id of this direct message.')
1066
950d53433f5b
1067
950d53433f5b
  def GetSenderScreenName(self):
1068
950d53433f5b
    '''Get the unique sender screen name of this direct message.
1069
950d53433f5b
1070
950d53433f5b
    Returns:
1071
950d53433f5b
      The unique sender screen name of this direct message
1072
950d53433f5b
    '''
1073
950d53433f5b
    return self._sender_screen_name
1074
950d53433f5b
1075
950d53433f5b
  def SetSenderScreenName(self, sender_screen_name):
1076
950d53433f5b
    '''Set the unique sender screen name of this direct message.
1077
950d53433f5b
1078
950d53433f5b
    Args:
1079
950d53433f5b
      sender_screen_name: The unique sender screen name of this direct message
1080
950d53433f5b
    '''
1081
950d53433f5b
    self._sender_screen_name = sender_screen_name
1082
950d53433f5b
1083
950d53433f5b
  sender_screen_name = property(GetSenderScreenName, SetSenderScreenName,
1084
950d53433f5b
                doc='The unique sender screen name of this direct message.')
1085
950d53433f5b
1086
950d53433f5b
  def GetRecipientId(self):
1087
950d53433f5b
    '''Get the unique recipient id of this direct message.
1088
950d53433f5b
1089
950d53433f5b
    Returns:
1090
950d53433f5b
      The unique recipient id of this direct message
1091
950d53433f5b
    '''
1092
950d53433f5b
    return self._recipient_id
1093
950d53433f5b
1094
950d53433f5b
  def SetRecipientId(self, recipient_id):
1095
950d53433f5b
    '''Set the unique recipient id of this direct message.
1096
950d53433f5b
1097
950d53433f5b
    Args:
1098
950d53433f5b
      recipient id: The unique recipient id of this direct message
1099
950d53433f5b
    '''
1100
950d53433f5b
    self._recipient_id = recipient_id
1101
950d53433f5b
1102
950d53433f5b
  recipient_id = property(GetRecipientId, SetRecipientId,
1103
950d53433f5b
                doc='The unique recipient id of this direct message.')
1104
950d53433f5b
1105
950d53433f5b
  def GetRecipientScreenName(self):
1106
950d53433f5b
    '''Get the unique recipient screen name of this direct message.
1107
950d53433f5b
1108
950d53433f5b
    Returns:
1109
950d53433f5b
      The unique recipient screen name of this direct message
1110
950d53433f5b
    '''
1111
950d53433f5b
    return self._recipient_screen_name
1112
950d53433f5b
1113
950d53433f5b
  def SetRecipientScreenName(self, recipient_screen_name):
1114
950d53433f5b
    '''Set the unique recipient screen name of this direct message.
1115
950d53433f5b
1116
950d53433f5b
    Args:
1117
950d53433f5b
      recipient_screen_name: The unique recipient screen name of this direct message
1118
950d53433f5b
    '''
1119
950d53433f5b
    self._recipient_screen_name = recipient_screen_name
1120
950d53433f5b
1121
950d53433f5b
  recipient_screen_name = property(GetRecipientScreenName, SetRecipientScreenName,
1122
950d53433f5b
                doc='The unique recipient screen name of this direct message.')
1123
950d53433f5b
1124
950d53433f5b
  def GetText(self):
1125
950d53433f5b
    '''Get the text of this direct message.
1126
950d53433f5b
1127
950d53433f5b
    Returns:
1128
950d53433f5b
      The text of this direct message.
1129
950d53433f5b
    '''
1130
950d53433f5b
    return self._text
1131
950d53433f5b
1132
950d53433f5b
  def SetText(self, text):
1133
950d53433f5b
    '''Set the text of this direct message.
1134
950d53433f5b
1135
950d53433f5b
    Args:
1136
950d53433f5b
      text: The text of this direct message
1137
950d53433f5b
    '''
1138
950d53433f5b
    self._text = text
1139
950d53433f5b
1140
950d53433f5b
  text = property(GetText, SetText,
1141
950d53433f5b
                  doc='The text of this direct message')
1142
950d53433f5b
1143
950d53433f5b
  def __ne__(self, other):
1144
950d53433f5b
    return not self.__eq__(other)
1145
950d53433f5b
1146
950d53433f5b
  def __eq__(self, other):
1147
950d53433f5b
    try:
1148
950d53433f5b
      return other and \
1149
950d53433f5b
          self.id == other.id and \
1150
950d53433f5b
          self.created_at == other.created_at and \
1151
950d53433f5b
          self.sender_id == other.sender_id and \
1152
950d53433f5b
          self.sender_screen_name == other.sender_screen_name and \
1153
950d53433f5b
          self.recipient_id == other.recipient_id and \
1154
950d53433f5b
          self.recipient_screen_name == other.recipient_screen_name and \
1155
950d53433f5b
          self.text == other.text
1156
950d53433f5b
    except AttributeError:
1157
950d53433f5b
      return False
1158
950d53433f5b
1159
950d53433f5b
  def __str__(self):
1160
950d53433f5b
    '''A string representation of this twitter.DirectMessage instance.
1161
950d53433f5b
1162
950d53433f5b
    The return value is the same as the JSON string representation.
1163
950d53433f5b
1164
950d53433f5b
    Returns:
1165
950d53433f5b
      A string representation of this twitter.DirectMessage instance.
1166
950d53433f5b
    '''
1167
950d53433f5b
    return self.AsJsonString()
1168
950d53433f5b
1169
950d53433f5b
  def AsJsonString(self):
1170
950d53433f5b
    '''A JSON string representation of this twitter.DirectMessage instance.
1171
950d53433f5b
1172
950d53433f5b
    Returns:
1173
950d53433f5b
      A JSON string representation of this twitter.DirectMessage instance
1174
950d53433f5b
   '''
1175
950d53433f5b
    return simplejson.dumps(self.AsDict(), sort_keys=True)
1176
950d53433f5b
1177
950d53433f5b
  def AsDict(self):
1178
950d53433f5b
    '''A dict representation of this twitter.DirectMessage instance.
1179
950d53433f5b
1180
950d53433f5b
    The return value uses the same key names as the JSON representation.
1181
950d53433f5b
1182
950d53433f5b
    Return:
1183
950d53433f5b
      A dict representing this twitter.DirectMessage instance
1184
950d53433f5b
    '''
1185
950d53433f5b
    data = {}
1186
950d53433f5b
    if self.id:
1187
950d53433f5b
      data['id'] = self.id
1188
950d53433f5b
    if self.created_at:
1189
950d53433f5b
      data['created_at'] = self.created_at
1190
950d53433f5b
    if self.sender_id:
1191
950d53433f5b
      data['sender_id'] = self.sender_id
1192
950d53433f5b
    if self.sender_screen_name:
1193
950d53433f5b
      data['sender_screen_name'] = self.sender_screen_name
1194
950d53433f5b
    if self.recipient_id:
1195
950d53433f5b
      data['recipient_id'] = self.recipient_id
1196
950d53433f5b
    if self.recipient_screen_name:
1197
950d53433f5b
      data['recipient_screen_name'] = self.recipient_screen_name
1198
950d53433f5b
    if self.text:
1199
950d53433f5b
      data['text'] = self.text
1200
950d53433f5b
    return data
1201
c42880b017af
1202
c42880b017af
  @staticmethod
1203
c42880b017af
  def NewFromJsonDict(data):
1204
c42880b017af
    '''Create a new instance based on a JSON dict.
1205
c42880b017af
1206
c42880b017af
    Args:
1207
c42880b017af
      data: A JSON dict, as converted from the JSON in the twitter API
1208
c42880b017af
    Returns:
1209
c42880b017af
      A twitter.DirectMessage instance
1210
c42880b017af
    '''
1211
c42880b017af
    return DirectMessage(created_at=data.get('created_at', None),
1212
c42880b017af
                         recipient_id=data.get('recipient_id', None),
1213
c42880b017af
                         sender_id=data.get('sender_id', None),
1214
c42880b017af
                         text=data.get('text', None),
1215
c42880b017af
                         sender_screen_name=data.get('sender_screen_name', None),
1216
c42880b017af
                         id=data.get('id', None),
1217
c42880b017af
                         recipient_screen_name=data.get('recipient_screen_name', None))
1218
4805aee792f0
1219
4805aee792f0
class Api(object):
1220
4805aee792f0
  '''A python interface into the Twitter API
1221
4805aee792f0
1222
4805aee792f0
  By default, the Api caches results for 1 minute.
1223
17f566981b41
1224
4805aee792f0
  Example usage:
1225
4805aee792f0
1226
ee84714ea665
    To create an instance of the twitter.Api class, with no authentication:
1227
4805aee792f0
1228
e67a0a1b407c
      >>> import twitter
1229
e67a0a1b407c
      >>> api = twitter.Api()
1230
4805aee792f0
1231
e67a0a1b407c
    To fetch the most recently posted public twitter status messages:
1232
4805aee792f0
1233
e67a0a1b407c
      >>> statuses = api.GetPublicTimeline()
1234
e67a0a1b407c
      >>> print [s.user.name for s in statuses]
1235
e67a0a1b407c
      [u'DeWitt', u'Kesuke Miyagi', u'ev', u'Buzz Andersen', u'Biz Stone'] #...
1236
4805aee792f0
1237
3e87a5de4fc0
    To fetch a single user's public status messages, where "user" is either
1238
3e87a5de4fc0
    a Twitter "short name" or their user id.
1239
4805aee792f0
1240
3e87a5de4fc0
      >>> statuses = api.GetUserTimeline(user)
1241
e67a0a1b407c
      >>> print [s.text for s in statuses]
1242
4805aee792f0
1243
ee84714ea665
    To use authentication, instantiate the twitter.Api class with a
1244
ee84714ea665
    username and password:
1245
e67a0a1b407c
1246
ee84714ea665
      >>> api = twitter.Api(username='twitter user', password='twitter pass')
1247
32a0266e88a8
1248
ee84714ea665
    To fetch your friends (after being authenticated):
1249
ee84714ea665
1250
ee84714ea665
      >>> users = api.GetFriends()
1251
e67a0a1b407c
      >>> print [u.name for u in users]
1252
e67a0a1b407c
1253
ee84714ea665
    To post a twitter status message (after being authenticated):
1254
17f566981b41
1255
ee84714ea665
      >>> status = api.PostUpdate('I love python-twitter!')
1256
e67a0a1b407c
      >>> print status.text
1257
e67a0a1b407c
      I love python-twitter!
1258
b9effe73b630
1259
b9effe73b630
    There are many other methods, including:
1260
b9effe73b630
1261
81cef10d2991
      >>> api.PostUpdates(status)
1262
b9effe73b630
      >>> api.PostDirectMessage(user, text)
1263
b9effe73b630
      >>> api.GetUser(user)
1264
b9effe73b630
      >>> api.GetReplies()
1265
b9effe73b630
      >>> api.GetUserTimeline(user)
1266
b9effe73b630
      >>> api.GetStatus(id)
1267
6c1724c3654d
      >>> api.DestroyStatus(id)
1268
b9effe73b630
      >>> api.GetFriendsTimeline(user)
1269
b9effe73b630
      >>> api.GetFriends(user)
1270
b9effe73b630
      >>> api.GetFollowers()
1271
b9effe73b630
      >>> api.GetFeatured()
1272
b9effe73b630
      >>> api.GetDirectMessages()
1273
b9effe73b630
      >>> api.PostDirectMessage(user, text)
1274
b9effe73b630
      >>> api.DestroyDirectMessage(id)
1275
b9effe73b630
      >>> api.DestroyFriendship(user)
1276
b9effe73b630
      >>> api.CreateFriendship(user)
1277
e2f8ed587060
      >>> api.GetUserByEmail(email)
1278
4805aee792f0
  '''
1279
4805aee792f0
1280
17f566981b41
  DEFAULT_CACHE_TIMEOUT = 60 # cache for 1 minute
1281
4805aee792f0
1282
4805aee792f0
  _API_REALM = 'Twitter API'
1283
17f566981b41
1284
90cd841771cf
  def __init__(self,
1285
90cd841771cf
               username=None,
1286
90cd841771cf
               password=None,
1287
90cd841771cf
               input_encoding=None,
1288
90cd841771cf
               request_headers=None):
1289
ee84714ea665
    '''Instantiate a new twitter.Api object.
1290
ee84714ea665
1291
ee84714ea665
    Args:
1292
ee84714ea665
      username: The username of the twitter account.  [optional]
1293
ee84714ea665
      password: The password for the twitter account. [optional]
1294
90cd841771cf
      input_encoding: The encoding used to encode input strings. [optional]
1295
90cd841771cf
      request_header: A dictionary of additional HTTP request headers. [optional]
1296
ee84714ea665
    '''
1297
4805aee792f0
    self._cache = _FileCache()
1298
4805aee792f0
    self._urllib = urllib2
1299
4805aee792f0
    self._cache_timeout = Api.DEFAULT_CACHE_TIMEOUT
1300
90cd841771cf
    self._InitializeRequestHeaders(request_headers)
1301
90cd841771cf
    self._InitializeUserAgent()
1302
cb10f131e83f
    self._InitializeDefaultParameters()
1303
4dfd36cb761d
    self._input_encoding = input_encoding
1304
ee84714ea665
    self.SetCredentials(username, password)
1305
4805aee792f0
1306
ee84714ea665
  def GetPublicTimeline(self, since_id=None):
1307
4805aee792f0
    '''Fetch the sequnce of public twitter.Status message for all users.
1308
4805aee792f0
1309
ee84714ea665
    Args:
1310
32a0266e88a8
      since_id:
1311
ee84714ea665
        Returns only public statuses with an ID greater than (that is,
1312
ee84714ea665
        more recent than) the specified ID. [Optional]
1313
32a0266e88a8
1314
4805aee792f0
    Returns:
1315
4805aee792f0
      An sequence of twitter.Status instances, one for each message
1316
4805aee792f0
    '''
1317
ee84714ea665
    parameters = {}
1318
ee84714ea665
    if since_id:
1319
ee84714ea665
      parameters['since_id'] = since_id
1320
4805aee792f0
    url = 'http://twitter.com/statuses/public_timeline.json'
1321
ee84714ea665
    json = self._FetchUrl(url,  parameters=parameters)
1322
4805aee792f0
    data = simplejson.loads(json)
1323
265fcf2a1e01
    self._CheckForTwitterError(data)
1324
4805aee792f0
    return [Status.NewFromJsonDict(x) for x in data]
1325
4805aee792f0
1326
11710035d0b9
  def GetFriendsTimeline(self,
1327
11710035d0b9
                         user=None,
1328
11710035d0b9
                         count=None,
1329
11710035d0b9
                         since=None, 
1330
11710035d0b9
                         since_id=None):
1331
ee84714ea665
    '''Fetch the sequence of twitter.Status messages for a user's friends
1332
ee84714ea665
1333
ee84714ea665
    The twitter.Api instance must be authenticated if the user is private.
1334
ee84714ea665
1335
ee84714ea665
    Args:
1336
32a0266e88a8
      user:
1337
ee84714ea665
        Specifies the ID or screen name of the user for whom to return
1338
32a0266e88a8
        the friends_timeline.  If unspecified, the username and password
1339
11710035d0b9
        must be set in the twitter.Api instance.  [Optional]
1340
11710035d0b9
      count: 
1341
11710035d0b9
        Specifies the number of statuses to retrieve. May not be
1342
11710035d0b9
        greater than 200. [Optional]
1343
ee84714ea665
      since:
1344
ee84714ea665
        Narrows the returned results to just those statuses created
1345
11710035d0b9
        after the specified HTTP-formatted date. [Optional]
1346
806829c7dc10
      since_id:
1347
806829c7dc10
        Returns only public statuses with an ID greater than (that is,
1348
806829c7dc10
        more recent than) the specified ID. [Optional]
1349
ee84714ea665
1350
ee84714ea665
    Returns:
1351
ee84714ea665
      A sequence of twitter.Status instances, one for each message
1352
ee84714ea665
    '''
1353
ee84714ea665
    if user:
1354
ee84714ea665
      url = 'http://twitter.com/statuses/friends_timeline/%s.json' % user
1355
ee84714ea665
    elif not user and not self._username:
1356
ee84714ea665
      raise TwitterError("User must be specified if API is not authenticated.")
1357
32a0266e88a8
    else:
1358
ee84714ea665
      url = 'http://twitter.com/statuses/friends_timeline.json'
1359
ee84714ea665
    parameters = {}
1360
11710035d0b9
    if count is not None:
1361
11710035d0b9
      try:
1362
11710035d0b9
        if int(count) > 200:
1363
11710035d0b9
          raise TwitterError("'count' may not be greater than 200")
1364
11710035d0b9
      except ValueError:
1365
11710035d0b9
        raise TwitterError("'count' must be an integer")
1366
11710035d0b9
      parameters['count'] = count
1367
ee84714ea665
    if since:
1368
ee84714ea665
      parameters['since'] = since
1369
806829c7dc10
    if since_id:
1370
806829c7dc10
      parameters['since_id'] = since_id
1371
ee84714ea665
    json = self._FetchUrl(url, parameters=parameters)
1372
ee84714ea665
    data = simplejson.loads(json)
1373
265fcf2a1e01
    self._CheckForTwitterError(data)
1374
ee84714ea665
    return [Status.NewFromJsonDict(x) for x in data]
1375
ee84714ea665
1376
806829c7dc10
  def GetUserTimeline(self, user=None, count=None, since=None, since_id=None):
1377
4805aee792f0
    '''Fetch the sequence of public twitter.Status messages for a single user.
1378
4805aee792f0
1379
ee84714ea665
    The twitter.Api instance must be authenticated if the user is private.
1380
ee84714ea665
1381
4805aee792f0
    Args:
1382
e565d3a31699
      user:
1383
32a0266e88a8
        either the username (short_name) or id of the user to retrieve.  If
1384
ee84714ea665
        not specified, then the current authenticated user is used. [optional]
1385
ee84714ea665
      count: the number of status messages to retrieve [optional]
1386
ee84714ea665
      since:
1387
ee84714ea665
        Narrows the returned results to just those statuses created
1388
ee84714ea665
        after the specified HTTP-formatted date. [optional]
1389
806829c7dc10
      since_id:
1390
806829c7dc10
        Returns only public statuses with an ID greater than (that is,
1391
806829c7dc10
        more recent than) the specified ID. [Optional]
1392
4805aee792f0
1393
4805aee792f0
    Returns:
1394
4805aee792f0
      A sequence of twitter.Status instances, one for each message up to count
1395
4805aee792f0
    '''
1396
4805aee792f0
    try:
1397
4805aee792f0
      if count:
1398
4805aee792f0
        int(count)
1399
4805aee792f0
    except:
1400
4805aee792f0
      raise TwitterError("Count must be an integer")
1401
ee84714ea665
    parameters = {}
1402
4805aee792f0
    if count:
1403
ee84714ea665
      parameters['count'] = count
1404
ee84714ea665
    if since:
1405
ee84714ea665
      parameters['since'] = since
1406
806829c7dc10
    if since_id:
1407
806829c7dc10
      parameters['since_id'] = since_id
1408
ee84714ea665
    if user:
1409
ee84714ea665
      url = 'http://twitter.com/statuses/user_timeline/%s.json' % user
1410
ee84714ea665
    elif not user and not self._username:
1411
ee84714ea665
      raise TwitterError("User must be specified if API is not authenticated.")
1412
4805aee792f0
    else:
1413
ee84714ea665
      url = 'http://twitter.com/statuses/user_timeline.json'
1414
4805aee792f0
    json = self._FetchUrl(url, parameters=parameters)
1415
4805aee792f0
    data = simplejson.loads(json)
1416
265fcf2a1e01
    self._CheckForTwitterError(data)
1417
4805aee792f0
    return [Status.NewFromJsonDict(x) for x in data]
1418
32a0266e88a8
1419
ee84714ea665
  def GetStatus(self, id):
1420
ee84714ea665
    '''Returns a single status message.
1421
4805aee792f0
1422
ee84714ea665
    The twitter.Api instance must be authenticated if the status message is private.
1423
4805aee792f0
1424
4805aee792f0
    Args:
1425
32a0266e88a8
      id: The numerical ID of the status you're trying to retrieve.
1426
4805aee792f0
1427
4805aee792f0
    Returns:
1428
ee84714ea665
      A twitter.Status instance representing that status message
1429
4805aee792f0
    '''
1430
ee84714ea665
    try:
1431
ee84714ea665
      if id:
1432
ee84714ea665
        int(id)
1433
ee84714ea665
    except:
1434
ee84714ea665
      raise TwitterError("id must be an integer")
1435
ee84714ea665
    url = 'http://twitter.com/statuses/show/%s.json' % id
1436
ee84714ea665
    json = self._FetchUrl(url)
1437
4805aee792f0
    data = simplejson.loads(json)
1438
265fcf2a1e01
    self._CheckForTwitterError(data)
1439
ee84714ea665
    return Status.NewFromJsonDict(data)
1440
4805aee792f0
1441
4da5ec4d173a
  def DestroyStatus(self, id):
1442
4da5ec4d173a
    '''Destroys the status specified by the required ID parameter.
1443
4da5ec4d173a
1444
4da5ec4d173a
    The twitter.Api instance must be authenticated and thee
1445
4da5ec4d173a
    authenticating user must be the author of the specified status.
1446
4da5ec4d173a
1447
4da5ec4d173a
    Args:
1448
4da5ec4d173a
      id: The numerical ID of the status you're trying to destroy.
1449
4da5ec4d173a
1450
4da5ec4d173a
    Returns:
1451
4da5ec4d173a
      A twitter.Status instance representing the destroyed status message
1452
4da5ec4d173a
    '''
1453
4da5ec4d173a
    try:
1454
4da5ec4d173a
      if id:
1455
4da5ec4d173a
        int(id)
1456
4da5ec4d173a
    except:
1457
4da5ec4d173a
      raise TwitterError("id must be an integer")
1458
4da5ec4d173a
    url = 'http://twitter.com/statuses/destroy/%s.json' % id
1459
4da5ec4d173a
    json = self._FetchUrl(url, post_data={})
1460
4da5ec4d173a
    data = simplejson.loads(json)
1461
265fcf2a1e01
    self._CheckForTwitterError(data)
1462
4da5ec4d173a
    return Status.NewFromJsonDict(data)
1463
4da5ec4d173a
1464
81cef10d2991
  def PostUpdate(self, status, in_reply_to_status_id=None):
1465
c42880b017af
    '''Post a twitter status message from the authenticated user.
1466
ee84714ea665
1467
ee84714ea665
    The twitter.Api instance must be authenticated.
1468
4805aee792f0
1469
4805aee792f0
    Args:
1470
81cef10d2991
      status:
1471
81cef10d2991
        The message text to be posted.  Must be less than or equal to
1472
81cef10d2991
        140 characters.
1473
71b5f9cae083
      in_reply_to_status_id:
1474
71b5f9cae083
        The ID of an existing status that the status to be posted is
1475
71b5f9cae083
        in reply to.  This implicitly sets the in_reply_to_user_id
1476
71b5f9cae083
        attribute of the resulting status to the user ID of the
1477
71b5f9cae083
        message being replied to.  Invalid/missing status IDs will be
1478
71b5f9cae083
        ignored. [Optional]
1479
4805aee792f0
    Returns:
1480
81cef10d2991
      A twitter.Status instance representing the message posted.
1481
4805aee792f0
    '''
1482
ee84714ea665
    if not self._username:
1483
ee84714ea665
      raise TwitterError("The twitter.Api instance must be authenticated.")
1484
81cef10d2991
1485
c42880b017af
    url = 'http://twitter.com/statuses/update.json'
1486
81cef10d2991
1487
81cef10d2991
    if len(status) > CHARACTER_LIMIT:
1488
81cef10d2991
      raise TwitterError("Text must be less than or equal to %d characters. "
1489
81cef10d2991
                         "Consider using PostUpdates." % CHARACTER_LIMIT)
1490
81cef10d2991
1491
81cef10d2991
    data = {'status': status}
1492
71b5f9cae083
    if in_reply_to_status_id:
1493
71b5f9cae083
      data['in_reply_to_status_id'] = in_reply_to_status_id
1494
79429eb1b54d
    json = self._FetchUrl(url, post_data=data)
1495
4805aee792f0
    data = simplejson.loads(json)
1496
265fcf2a1e01
    self._CheckForTwitterError(data)
1497
4805aee792f0
    return Status.NewFromJsonDict(data)
1498
4805aee792f0
1499
8bdda4c8187b
  def PostUpdates(self, status, continuation=None, **kwargs):
1500
81cef10d2991
    '''Post one or more twitter status messages from the authenticated user.
1501
81cef10d2991
1502
81cef10d2991
    Unlike api.PostUpdate, this method will post multiple status updates
1503
81cef10d2991
    if the message is longer than 140 characters.
1504
81cef10d2991
1505
81cef10d2991
    The twitter.Api instance must be authenticated.
1506
81cef10d2991
1507
81cef10d2991
    Args:
1508
81cef10d2991
      status:
1509
81cef10d2991
        The message text to be posted.  May be longer than 140 characters.
1510
8bdda4c8187b
      continuation:
1511
8bdda4c8187b
        The character string, if any, to be appended to all but the
1512
8bdda4c8187b
        last message.  Note that Twitter strips trailing '...' strings
1513
8bdda4c8187b
        from messages.  Consider using the unicode \u2026 character
1514
8bdda4c8187b
        (horizontal ellipsis) instead. [Defaults to None]
1515
81cef10d2991
      **kwargs:
1516
81cef10d2991
        See api.PostUpdate for a list of accepted parameters.
1517
81cef10d2991
    Returns:
1518
81cef10d2991
      A of list twitter.Status instance representing the messages posted.
1519
81cef10d2991
    '''
1520
81cef10d2991
    results = list()
1521
8bdda4c8187b
    if continuation is None:
1522
8bdda4c8187b
      continuation = ''
1523
8bdda4c8187b
    line_length = CHARACTER_LIMIT - len(continuation)
1524
8bdda4c8187b
    lines = textwrap.wrap(status, line_length)
1525
8bdda4c8187b
    for line in lines[0:-1]:
1526
8bdda4c8187b
      results.append(self.PostUpdate(line + continuation, **kwargs))
1527
8bdda4c8187b
    results.append(self.PostUpdate(lines[-1], **kwargs))
1528
81cef10d2991
    return results
1529
81cef10d2991
1530
935cf080b638
  def GetReplies(self, since=None, since_id=None, page=None): 
1531
ee84714ea665
    '''Get a sequence of status messages representing the 20 most recent
1532
ee84714ea665
    replies (status updates prefixed with @username) to the authenticating
1533
ee84714ea665
    user.
1534
71b5f9cae083
1535
a10f9a46dc3d
    Args:
1536
935cf080b638
      page: 
1537
a10f9a46dc3d
      since:
1538
a10f9a46dc3d
        Narrows the returned results to just those statuses created
1539
a10f9a46dc3d
        after the specified HTTP-formatted date. [optional]
1540
a10f9a46dc3d
      since_id:
1541
a10f9a46dc3d
        Returns only public statuses with an ID greater than (that is,
1542
a10f9a46dc3d
        more recent than) the specified ID. [Optional]
1543
ee84714ea665
1544
ee84714ea665
    Returns:
1545
ee84714ea665
      A sequence of twitter.Status instances, one for each reply to the user.
1546
32a0266e88a8
    '''
1547
ee84714ea665
    url = 'http://twitter.com/statuses/replies.json'
1548
ee84714ea665
    if not self._username:
1549
ee84714ea665
      raise TwitterError("The twitter.Api instance must be authenticated.")
1550
a10f9a46dc3d
    parameters = {}
1551
a10f9a46dc3d
    if since:
1552
a10f9a46dc3d
      parameters['since'] = since
1553
a10f9a46dc3d
    if since_id:
1554
a10f9a46dc3d
      parameters['since_id'] = since_id
1555
935cf080b638
    if page:
1556
935cf080b638
      parameters['page'] = page
1557
a10f9a46dc3d
    json = self._FetchUrl(url, parameters=parameters)
1558
ee84714ea665
    data = simplejson.loads(json)
1559
265fcf2a1e01
    self._CheckForTwitterError(data)
1560
ee84714ea665
    return [Status.NewFromJsonDict(x) for x in data]
1561
ee84714ea665
1562
82aae45f64f2
  def GetMentions(self, since_id=None, max_id=None, count=None,  page=None):
1563
82aae45f64f2
    '''Returns a list of mentions of the authenticating user.
1564
82aae45f64f2
1565
82aae45f64f2
    The twitter.Api instance must be authenticated.
1566
82aae45f64f2
1567
82aae45f64f2
    Args:
1568
82aae45f64f2
      since_id:
1569
82aae45f64f2
        Returns only public statuses with an ID greater than (that is,
1570
82aae45f64f2
        more recent than) the specified ID. [Optional]
1571
82aae45f64f2
      max_id:
1572
82aae45f64f2
        Optional. Returns only statuses with an ID less than (that is, older than)
1573
82aae45f64f2
        or equal to the specified ID.
1574
82aae45f64f2
      count:
1575
82aae45f64f2
        Optional. Specifies the number of statuses to retrieve. May not be greater
1576
82aae45f64f2
        than 200.
1577
82aae45f64f2
1578
82aae45f64f2
    Returns:
1579
82aae45f64f2
      A sequence of twitter.Status instances
1580
82aae45f64f2
    '''
1581
82aae45f64f2
    url = 'http://twitter.com/statuses/mentions.json'
1582
82aae45f64f2
    if not self._username:
1583
82aae45f64f2
      raise TwitterError("The twitter.Api instance must be authenticated.")
1584
82aae45f64f2
    parameters = {}
1585
82aae45f64f2
    if since_id:
1586
82aae45f64f2
      parameters['since_id'] = since_id
1587
82aae45f64f2
    if max_id:
1588
82aae45f64f2
      parameters['max_id'] = max_id
1589
82aae45f64f2
    if count:
1590
82aae45f64f2
      parameters['count'] = count
1591
82aae45f64f2
    if page:
1592
82aae45f64f2
      parameters['page'] = page 
1593
82aae45f64f2
    json = self._FetchUrl(url, parameters=parameters)
1594
82aae45f64f2
    data = simplejson.loads(json)
1595
82aae45f64f2
    self._CheckForTwitterError(data)
1596
82aae45f64f2
    return [Status.NewFromJsonDict(x) for x in data]
1597
82aae45f64f2
    
1598
935cf080b638
  def GetFriends(self, user=None, page=None):
1599
ee84714ea665
    '''Fetch the sequence of twitter.User instances, one for each friend.
1600
ee84714ea665
1601
ee84714ea665
    Args:
1602
ee84714ea665
      user: the username or id of the user whose friends you are fetching.  If
1603
ee84714ea665
      not specified, defaults to the authenticated user. [optional]
1604
ee84714ea665
1605
ee84714ea665
    The twitter.Api instance must be authenticated.
1606
ee84714ea665
1607
ee84714ea665
    Returns:
1608
ee84714ea665
      A sequence of twitter.User instances, one for each friend
1609
ee84714ea665
    '''
1610
ee84714ea665
    if not self._username:
1611
ee84714ea665
      raise TwitterError("twitter.Api instance must be authenticated")
1612
ee84714ea665
    if user:
1613
935cf080b638
      url = 'http://twitter.com/statuses/friends/%s.json' % user 
1614
32a0266e88a8
    else:
1615
ee84714ea665
      url = 'http://twitter.com/statuses/friends.json'
1616
935cf080b638
    parameters = {}
1617
935cf080b638
    if page:
1618
935cf080b638
      parameters['page'] = page
1619
935cf080b638
    json = self._FetchUrl(url, parameters=parameters)
1620
ee84714ea665
    data = simplejson.loads(json)
1621
265fcf2a1e01
    self._CheckForTwitterError(data)
1622
ee84714ea665
    return [User.NewFromJsonDict(x) for x in data]
1623
ee84714ea665
1624
935cf080b638
  def GetFollowers(self, page=None):
1625
ee84714ea665
    '''Fetch the sequence of twitter.User instances, one for each follower
1626
ee84714ea665
1627
ee84714ea665
    The twitter.Api instance must be authenticated.
1628
ee84714ea665
1629
ee84714ea665
    Returns:
1630
ee84714ea665
      A sequence of twitter.User instances, one for each follower
1631
ee84714ea665
    '''
1632
ee84714ea665
    if not self._username:
1633
ee84714ea665
      raise TwitterError("twitter.Api instance must be authenticated")
1634
ee84714ea665
    url = 'http://twitter.com/statuses/followers.json'
1635
935cf080b638
    parameters = {}
1636
935cf080b638
    if page:
1637
935cf080b638
      parameters['page'] = page
1638
935cf080b638
    json = self._FetchUrl(url, parameters=parameters)
1639
ee84714ea665
    data = simplejson.loads(json)
1640
265fcf2a1e01
    self._CheckForTwitterError(data)
1641
ee84714ea665
    return [User.NewFromJsonDict(x) for x in data]
1642
ee84714ea665
1643
e3638dafb13c
  def GetFeatured(self):
1644
e3638dafb13c
    '''Fetch the sequence of twitter.User instances featured on twitter.com
1645
e3638dafb13c
1646
e3638dafb13c
    The twitter.Api instance must be authenticated.
1647
e3638dafb13c
1648
e3638dafb13c
    Returns:
1649
e3638dafb13c
      A sequence of twitter.User instances
1650
e3638dafb13c
    '''
1651
e3638dafb13c
    url = 'http://twitter.com/statuses/featured.json'
1652
e3638dafb13c
    json = self._FetchUrl(url)
1653
e3638dafb13c
    data = simplejson.loads(json)
1654
265fcf2a1e01
    self._CheckForTwitterError(data)
1655
e3638dafb13c
    return [User.NewFromJsonDict(x) for x in data]
1656
e3638dafb13c
1657
ee84714ea665
  def GetUser(self, user):
1658
ee84714ea665
    '''Returns a single user.
1659
ee84714ea665
1660
ee84714ea665
    The twitter.Api instance must be authenticated.
1661
ee84714ea665
1662
ee84714ea665
    Args:
1663
ee84714ea665
      user: The username or id of the user to retrieve.
1664
ee84714ea665
1665
ee84714ea665
    Returns:
1666
ee84714ea665
      A twitter.User instance representing that user
1667
ee84714ea665
    '''
1668
ee84714ea665
    url = 'http://twitter.com/users/show/%s.json' % user
1669
ee84714ea665
    json = self._FetchUrl(url)
1670
ee84714ea665
    data = simplejson.loads(json)
1671
265fcf2a1e01
    self._CheckForTwitterError(data)
1672
ee84714ea665
    return User.NewFromJsonDict(data)
1673
82aae45f64f2
    
1674
935cf080b638
  def GetDirectMessages(self, since=None, since_id=None, page=None):
1675
90377483d9fa
    '''Returns a list of the direct messages sent to the authenticating user.
1676
90377483d9fa
1677
90377483d9fa
    The twitter.Api instance must be authenticated.
1678
90377483d9fa
1679
32a0266e88a8
    Args:
1680
90377483d9fa
      since:
1681
90377483d9fa
        Narrows the returned results to just those statuses created
1682
90377483d9fa
        after the specified HTTP-formatted date. [optional]
1683
472ef0f2ea07
      since_id:
1684
472ef0f2ea07
        Returns only public statuses with an ID greater than (that is,
1685
472ef0f2ea07
        more recent than) the specified ID. [Optional]
1686
90377483d9fa
1687
90377483d9fa
    Returns:
1688
32a0266e88a8
      A sequence of twitter.DirectMessage instances
1689
90377483d9fa
    '''
1690
90377483d9fa
    url = 'http://twitter.com/direct_messages.json'
1691
90377483d9fa
    if not self._username:
1692
90377483d9fa
      raise TwitterError("The twitter.Api instance must be authenticated.")
1693
90377483d9fa
    parameters = {}
1694
90377483d9fa
    if since:
1695
90377483d9fa
      parameters['since'] = since
1696
472ef0f2ea07
    if since_id:
1697
472ef0f2ea07
      parameters['since_id'] = since_id
1698
935cf080b638
    if page:
1699
935cf080b638
      parameters['page'] = page 
1700
90377483d9fa
    json = self._FetchUrl(url, parameters=parameters)
1701
90377483d9fa
    data = simplejson.loads(json)
1702
265fcf2a1e01
    self._CheckForTwitterError(data)
1703
c42880b017af
    return [DirectMessage.NewFromJsonDict(x) for x in data]
1704
32a0266e88a8
1705
c42880b017af
  def PostDirectMessage(self, user, text):
1706
c42880b017af
    '''Post a twitter direct message from the authenticated user
1707
c42880b017af
1708
c42880b017af
    The twitter.Api instance must be authenticated.
1709
c42880b017af
1710
c42880b017af
    Args:
1711
c42880b017af
      user: The ID or screen name of the recipient user.
1712
c42880b017af
      text: The message text to be posted.  Must be less than 140 characters.
1713
c42880b017af
1714
c42880b017af
    Returns:
1715
32a0266e88a8
      A twitter.DirectMessage instance representing the message posted
1716
c42880b017af
    '''
1717
c42880b017af
    if not self._username:
1718
c42880b017af
      raise TwitterError("The twitter.Api instance must be authenticated.")
1719
c42880b017af
    url = 'http://twitter.com/direct_messages/new.json'
1720
c42880b017af
    data = {'text': text, 'user': user}
1721
79429eb1b54d
    json = self._FetchUrl(url, post_data=data)
1722
32a0266e88a8
    data = simplejson.loads(json)
1723
265fcf2a1e01
    self._CheckForTwitterError(data)
1724
32a0266e88a8
    return DirectMessage.NewFromJsonDict(data)
1725
32a0266e88a8
1726
32a0266e88a8
  def DestroyDirectMessage(self, id):
1727
32a0266e88a8
    '''Destroys the direct message specified in the required ID parameter.
1728
32a0266e88a8
1729
32a0266e88a8
    The twitter.Api instance must be authenticated, and the
1730
32a0266e88a8
    authenticating user must be the recipient of the specified direct
1731
32a0266e88a8
    message.
1732
32a0266e88a8
1733
32a0266e88a8
    Args:
1734
32a0266e88a8
      id: The id of the direct message to be destroyed
1735
32a0266e88a8
1736
32a0266e88a8
    Returns:
1737
32a0266e88a8
      A twitter.DirectMessage instance representing the message destroyed
1738
32a0266e88a8
    '''
1739
32a0266e88a8
    url = 'http://twitter.com/direct_messages/destroy/%s.json' % id
1740
79429eb1b54d
    json = self._FetchUrl(url, post_data={})
1741
c42880b017af
    data = simplejson.loads(json)
1742
265fcf2a1e01
    self._CheckForTwitterError(data)
1743
c42880b017af
    return DirectMessage.NewFromJsonDict(data)
1744
90377483d9fa
1745
79429eb1b54d
  def CreateFriendship(self, user):
1746
79429eb1b54d
    '''Befriends the user specified in the user parameter as the authenticating user.
1747
79429eb1b54d
1748
79429eb1b54d
    The twitter.Api instance must be authenticated.
1749
79429eb1b54d
1750
79429eb1b54d
    Args:
1751
79429eb1b54d
      The ID or screen name of the user to befriend.
1752
79429eb1b54d
    Returns:
1753
79429eb1b54d
      A twitter.User instance representing the befriended user.
1754
79429eb1b54d
    '''
1755
79429eb1b54d
    url = 'http://twitter.com/friendships/create/%s.json' % user
1756
79429eb1b54d
    json = self._FetchUrl(url, post_data={})
1757
79429eb1b54d
    data = simplejson.loads(json)
1758
265fcf2a1e01
    self._CheckForTwitterError(data)
1759
79429eb1b54d
    return User.NewFromJsonDict(data)
1760
79429eb1b54d
1761
79429eb1b54d
  def DestroyFriendship(self, user):
1762
79429eb1b54d
    '''Discontinues friendship with the user specified in the user parameter.
1763
79429eb1b54d
1764
79429eb1b54d
    The twitter.Api instance must be authenticated.
1765
79429eb1b54d
1766
79429eb1b54d
    Args:
1767
79429eb1b54d
      The ID or screen name of the user  with whom to discontinue friendship.
1768
79429eb1b54d
    Returns:
1769
79429eb1b54d
      A twitter.User instance representing the discontinued friend.
1770
79429eb1b54d
    '''
1771
79429eb1b54d
    url = 'http://twitter.com/friendships/destroy/%s.json' % user
1772
79429eb1b54d
    json = self._FetchUrl(url, post_data={})
1773
79429eb1b54d
    data = simplejson.loads(json)
1774
265fcf2a1e01
    self._CheckForTwitterError(data)
1775
79429eb1b54d
    return User.NewFromJsonDict(data)
1776
79429eb1b54d
1777
a1e65b8c9435
  def CreateFavorite(self, status):
1778
a1e65b8c9435
    '''Favorites the status specified in the status parameter as the authenticating user.
1779
a1e65b8c9435
    Returns the favorite status when successful.
1780
a1e65b8c9435
1781
a1e65b8c9435
    The twitter.Api instance must be authenticated.
1782
a1e65b8c9435
1783
a1e65b8c9435
    Args:
1784
a1e65b8c9435
      The twitter.Status instance to mark as a favorite.
1785
a1e65b8c9435
    Returns:
1786
a1e65b8c9435
      A twitter.Status instance representing the newly-marked favorite.
1787
a1e65b8c9435
    '''
1788
a1e65b8c9435
    url = 'http://twitter.com/favorites/create/%s.json' % status.id
1789
a1e65b8c9435
    json = self._FetchUrl(url, post_data={})
1790
a1e65b8c9435
    data = simplejson.loads(json)
1791
265fcf2a1e01
    self._CheckForTwitterError(data)
1792
a1e65b8c9435
    return Status.NewFromJsonDict(data)
1793
a1e65b8c9435
1794
a1e65b8c9435
  def DestroyFavorite(self, status):
1795
a1e65b8c9435
    '''Un-favorites the status specified in the ID parameter as the authenticating user.
1796
a1e65b8c9435
    Returns the un-favorited status in the requested format when successful.
1797
a1e65b8c9435
1798
a1e65b8c9435
    The twitter.Api instance must be authenticated.
1799
a1e65b8c9435
1800
a1e65b8c9435
    Args:
1801
a1e65b8c9435
      The twitter.Status to unmark as a favorite.
1802
a1e65b8c9435
    Returns:
1803
a1e65b8c9435
      A twitter.Status instance representing the newly-unmarked favorite.
1804
a1e65b8c9435
    '''
1805
a1e65b8c9435
    url = 'http://twitter.com/favorites/destroy/%s.json' % status.id
1806
a1e65b8c9435
    json = self._FetchUrl(url, post_data={})
1807
a1e65b8c9435
    data = simplejson.loads(json)
1808
265fcf2a1e01
    self._CheckForTwitterError(data)
1809
a1e65b8c9435
    return Status.NewFromJsonDict(data)
1810
a1e65b8c9435
1811
e2f8ed587060
  def GetUserByEmail(self, email):
1812
e2f8ed587060
    '''Returns a single user by email address.
1813
e2f8ed587060
1814
e2f8ed587060
    Args:
1815
e2f8ed587060
      email: The email of the user to retrieve.
1816
e2f8ed587060
    Returns:
1817
e2f8ed587060
      A twitter.User instance representing that user
1818
e2f8ed587060
    '''
1819
e2f8ed587060
    url = 'http://twitter.com/users/show.json?email=%s' % email
1820
e2f8ed587060
    json = self._FetchUrl(url)
1821
e2f8ed587060
    data = simplejson.loads(json)
1822
265fcf2a1e01
    self._CheckForTwitterError(data)
1823
e2f8ed587060
    return User.NewFromJsonDict(data)
1824
e2f8ed587060
1825
ee84714ea665
  def SetCredentials(self, username, password):
1826
ee84714ea665
    '''Set the username and password for this instance
1827
ee84714ea665
1828
ee84714ea665
    Args:
1829
ee84714ea665
      username: The twitter username.
1830
ee84714ea665
      password: The twitter password.
1831
ee84714ea665
    '''
1832
ee84714ea665
    self._username = username
1833
ee84714ea665
    self._password = password
1834
ee84714ea665
1835
ee84714ea665
  def ClearCredentials(self):
1836
ee84714ea665
    '''Clear the username and password for this instance
1837
ee84714ea665
    '''
1838
ee84714ea665
    self._username = None
1839
ee84714ea665
    self._password = None
1840
4805aee792f0
1841
4805aee792f0
  def SetCache(self, cache):
1842
4805aee792f0
    '''Override the default cache.  Set to None to prevent caching.
1843
4805aee792f0
1844
4805aee792f0
    Args:
1845
4805aee792f0
      cache: an instance that supports the same API as the  twitter._FileCache
1846
4805aee792f0
    '''
1847
4805aee792f0
    self._cache = cache
1848
4805aee792f0
1849
4805aee792f0
  def SetUrllib(self, urllib):
1850
4805aee792f0
    '''Override the default urllib implementation.
1851
4805aee792f0
1852
4805aee792f0
    Args:
1853
4805aee792f0
      urllib: an instance that supports the same API as the urllib2 module
1854
4805aee792f0
    '''
1855
4805aee792f0
    self._urllib = urllib
1856
4805aee792f0
1857
4805aee792f0
  def SetCacheTimeout(self, cache_timeout):
1858
4805aee792f0
    '''Override the default cache timeout.
1859
4805aee792f0
1860
4805aee792f0
    Args:
1861
4805aee792f0
      cache_timeout: time, in seconds, that responses should be reused.
1862
4805aee792f0
    '''
1863
4805aee792f0
    self._cache_timeout = cache_timeout
1864
4805aee792f0
1865
4805aee792f0
  def SetUserAgent(self, user_agent):
1866
4805aee792f0
    '''Override the default user agent
1867
4805aee792f0
1868
4805aee792f0
    Args:
1869
4805aee792f0
      user_agent: a string that should be send to the server as the User-agent
1870
4805aee792f0
    '''
1871
90cd841771cf
    self._request_headers['User-Agent'] = user_agent
1872
90cd841771cf
1873
90cd841771cf
  def SetXTwitterHeaders(self, client, url, version):
1874
90cd841771cf
    '''Set the X-Twitter HTTP headers that will be sent to the server.
1875
90cd841771cf
1876
90cd841771cf
    Args:
1877
90cd841771cf
      client:
1878
90cd841771cf
         The client name as a string.  Will be sent to the server as
1879
90cd841771cf
         the 'X-Twitter-Client' header.
1880
90cd841771cf
      url:
1881
90cd841771cf
         The URL of the meta.xml as a string.  Will be sent to the server
1882
90cd841771cf
         as the 'X-Twitter-Client-URL' header.
1883
90cd841771cf
      version:
1884
90cd841771cf
         The client version as a string.  Will be sent to the server
1885
90cd841771cf
         as the 'X-Twitter-Client-Version' header.
1886
90cd841771cf
    '''
1887
90cd841771cf
    self._request_headers['X-Twitter-Client'] = client
1888
90cd841771cf
    self._request_headers['X-Twitter-Client-URL'] = url
1889
90cd841771cf
    self._request_headers['X-Twitter-Client-Version'] = version
1890
4805aee792f0
1891
cb10f131e83f
  def SetSource(self, source):
1892
cb10f131e83f
    '''Suggest the "from source" value to be displayed on the Twitter web site.
1893
cb10f131e83f
1894
cb10f131e83f
    The value of the 'source' parameter must be first recognized by
1895
cb10f131e83f
    the Twitter server.  New source values are authorized on a case by
1896
cb10f131e83f
    case basis by the Twitter development team.
1897
cb10f131e83f
1898
cb10f131e83f
    Args:
1899
cb10f131e83f
      source:
1900
cb10f131e83f
        The source name as a string.  Will be sent to the server as
1901
cb10f131e83f
        the 'source' parameter.
1902
cb10f131e83f
    '''
1903
cb10f131e83f
    self._default_params['source'] = source
1904
cb10f131e83f
1905
4805aee792f0
  def _BuildUrl(self, url, path_elements=None, extra_params=None):
1906
4805aee792f0
    # Break url into consituent parts
1907
4805aee792f0
    (scheme, netloc, path, params, query, fragment) = urlparse.urlparse(url)
1908
17f566981b41
1909
4805aee792f0
    # Add any additional path elements to the path
1910
4805aee792f0
    if path_elements:
1911
4805aee792f0
      # Filter out the path elements that have a value of None
1912
4805aee792f0
      p = [i for i in path_elements if i]
1913
4805aee792f0
      if not path.endswith('/'):
1914
4805aee792f0
        path += '/'
1915
4805aee792f0
      path += '/'.join(p)
1916
17f566981b41
1917
4805aee792f0
    # Add any additional query parameters to the query string
1918
4805aee792f0
    if extra_params and len(extra_params) > 0:
1919
32a0266e88a8
      extra_query = self._EncodeParameters(extra_params)
1920
b0bbd9fa96ce
      # Add it to the existing query
1921
b0bbd9fa96ce
      if query:
1922
b0bbd9fa96ce
        query += '&' + extra_query
1923
b0bbd9fa96ce
      else:
1924
b0bbd9fa96ce
        query = extra_query
1925
17f566981b41
1926
4805aee792f0
    # Return the rebuilt URL
1927
4805aee792f0
    return urlparse.urlunparse((scheme, netloc, path, params, query, fragment))
1928
4805aee792f0
1929
90cd841771cf
  def _InitializeRequestHeaders(self, request_headers):
1930
90cd841771cf
    if request_headers:
1931
90cd841771cf
      self._request_headers = request_headers
1932
90cd841771cf
    else:
1933
90cd841771cf
      self._request_headers = {}
1934
90cd841771cf
1935
90cd841771cf
  def _InitializeUserAgent(self):
1936
90cd841771cf
    user_agent = 'Python-urllib/%s (python-twitter/%s)' % \
1937
0ef37898cd2b
                 (self._urllib.__version__, __version__)
1938
90cd841771cf
    self.SetUserAgent(user_agent)
1939
90cd841771cf
1940
cb10f131e83f
  def _InitializeDefaultParameters(self):
1941
cb10f131e83f
    self._default_params = {}
1942
cb10f131e83f
1943
f73c99cf9b51
  def _AddAuthorizationHeader(self, username, password):
1944
f73c99cf9b51
    if username and password:
1945
f73c99cf9b51
      basic_auth = base64.encodestring('%s:%s' % (username, password))[:-1]
1946
f73c99cf9b51
      self._request_headers['Authorization'] = 'Basic %s' % basic_auth
1947
f73c99cf9b51
1948
f73c99cf9b51
  def _RemoveAuthorizationHeader(self):
1949
f73c99cf9b51
    if self._request_headers and 'Authorization' in self._request_headers:
1950
f73c99cf9b51
      del self._request_headers['Authorization']
1951
f73c99cf9b51
1952
4805aee792f0
  def _GetOpener(self, url, username=None, password=None):
1953
4805aee792f0
    if username and password:
1954
f73c99cf9b51
      self._AddAuthorizationHeader(username, password)
1955
4805aee792f0
      handler = self._urllib.HTTPBasicAuthHandler()
1956
4805aee792f0
      (scheme, netloc, path, params, query, fragment) = urlparse.urlparse(url)
1957
4805aee792f0
      handler.add_password(Api._API_REALM, netloc, username, password)
1958
4805aee792f0
      opener = self._urllib.build_opener(handler)
1959
4805aee792f0
    else:
1960
4805aee792f0
      opener = self._urllib.build_opener()
1961
90cd841771cf
    opener.addheaders = self._request_headers.items()
1962
4805aee792f0
    return opener
1963
4805aee792f0
1964
4dfd36cb761d
  def _Encode(self, s):
1965
4dfd36cb761d
    if self._input_encoding:
1966
4dfd36cb761d
      return unicode(s, self._input_encoding).encode('utf-8')
1967
4dfd36cb761d
    else:
1968
4dfd36cb761d
      return unicode(s).encode('utf-8')
1969
4dfd36cb761d
1970
32a0266e88a8
  def _EncodeParameters(self, parameters):
1971
32a0266e88a8
    '''Return a string in key=value&key=value form
1972
32a0266e88a8
1973
32a0266e88a8
    Values of None are not included in the output string.
1974
32a0266e88a8
1975
32a0266e88a8
    Args:
1976
32a0266e88a8
      parameters:
1977
32a0266e88a8
        A dict of (key, value) tuples, where value is encoded as
1978
32a0266e88a8
        specified by self._encoding
1979
32a0266e88a8
    Returns:
1980
32a0266e88a8
      A URL-encoded string in "key=value&key=value" form
1981
32a0266e88a8
    '''
1982
32a0266e88a8
    if parameters is None:
1983
32a0266e88a8
      return None
1984
32a0266e88a8
    else:
1985
4dfd36cb761d
      return urllib.urlencode(dict([(k, self._Encode(v)) for k, v in parameters.items() if v is not None]))
1986
32a0266e88a8
1987
32a0266e88a8
  def _EncodePostData(self, post_data):
1988
32a0266e88a8
    '''Return a string in key=value&key=value form
1989
32a0266e88a8
1990
32a0266e88a8
    Values are assumed to be encoded in the format specified by self._encoding,
1991
32a0266e88a8
    and are subsequently URL encoded.
1992
32a0266e88a8
1993
32a0266e88a8
    Args:
1994
32a0266e88a8
      post_data:
1995
32a0266e88a8
        A dict of (key, value) tuples, where value is encoded as
1996
32a0266e88a8
        specified by self._encoding
1997
32a0266e88a8
    Returns:
1998
32a0266e88a8
      A URL-encoded string in "key=value&key=value" form
1999
32a0266e88a8
    '''
2000
32a0266e88a8
    if post_data is None:
2001
32a0266e88a8
      return None
2002
32a0266e88a8
    else:
2003
4dfd36cb761d
      return urllib.urlencode(dict([(k, self._Encode(v)) for k, v in post_data.items()]))
2004
32a0266e88a8
2005
265fcf2a1e01
  def _CheckForTwitterError(self, data):
2006
265fcf2a1e01
    """Raises a TwitterError if twitter returns an error message.
2007
265fcf2a1e01
2008
265fcf2a1e01
    Args:
2009
265fcf2a1e01
      data: A python dict created from the Twitter json response
2010
265fcf2a1e01
    Raises:
2011
265fcf2a1e01
      TwitterError wrapping the twitter error message if one exists.
2012
265fcf2a1e01
    """
2013
265fcf2a1e01
    # Twitter errors are relatively unlikely, so it is faster
2014
265fcf2a1e01
    # to check first, rather than try and catch the exception
2015
265fcf2a1e01
    if 'error' in data:
2016
265fcf2a1e01
      raise TwitterError(data['error'])
2017
265fcf2a1e01
2018
4805aee792f0
  def _FetchUrl(self,
2019
4805aee792f0
                url,
2020
32a0266e88a8
                post_data=None,
2021
4805aee792f0
                parameters=None,
2022
4805aee792f0
                no_cache=None):
2023
ed04d2ff26fc
    '''Fetch a URL, optionally caching for a specified time.
2024
4805aee792f0
2025
4805aee792f0
    Args:
2026
4805aee792f0
      url: The URL to retrieve
2027
b02aa8558d4f
      post_data: 
2028
b02aa8558d4f
        A dict of (str, unicode) key/value pairs.  If set, POST will be used.
2029
b02aa8558d4f
      parameters:
2030
b02aa8558d4f
        A dict whose key/value pairs should encoded and added 
2031
b02aa8558d4f
        to the query string. [OPTIONAL]
2032
4805aee792f0
      no_cache: If true, overrides the cache on the current request
2033
4805aee792f0
2034
4805aee792f0
    Returns:
2035
4805aee792f0
      A string containing the body of the response.
2036
ed04d2ff26fc
    '''
2037
cb10f131e83f
    # Build the extra parameters dict
2038
cb10f131e83f
    extra_params = {}
2039
cb10f131e83f
    if self._default_params:
2040
cb10f131e83f
      extra_params.update(self._default_params)
2041
cb10f131e83f
    if parameters:
2042
cb10f131e83f
      extra_params.update(parameters)
2043
cb10f131e83f
2044
4805aee792f0
    # Add key/value parameters to the query string of the url
2045
cb10f131e83f
    url = self._BuildUrl(url, extra_params=extra_params)
2046
4805aee792f0
2047
4805aee792f0
    # Get a url opener that can handle basic auth
2048
ee84714ea665
    opener = self._GetOpener(url, username=self._username, password=self._password)
2049
4805aee792f0
2050
32a0266e88a8
    encoded_post_data = self._EncodePostData(post_data)
2051
c42880b017af
2052
4805aee792f0
    # Open and return the URL immediately if we're not going to cache
2053
32a0266e88a8
    if encoded_post_data or no_cache or not self._cache or not self._cache_timeout:
2054
32a0266e88a8
      url_data = opener.open(url, encoded_post_data).read()
2055
c1d12896a51f
      opener.close()
2056
4805aee792f0
    else:
2057
4805aee792f0
      # Unique keys are a combination of the url and the username
2058
ee84714ea665
      if self._username:
2059
ee84714ea665
        key = self._username + ':' + url
2060
4805aee792f0
      else:
2061
4805aee792f0
        key = url
2062
4805aee792f0
2063
4805aee792f0
      # See if it has been cached before
2064
4805aee792f0
      last_cached = self._cache.GetCachedTime(key)
2065
4805aee792f0
2066
4805aee792f0
      # If the cached version is outdated then fetch another and store it
2067
4805aee792f0
      if not last_cached or time.time() >= last_cached + self._cache_timeout:
2068
32a0266e88a8
        url_data = opener.open(url, encoded_post_data).read()
2069
c1d12896a51f
        opener.close()
2070
4805aee792f0
        self._cache.Set(key, url_data)
2071
4805aee792f0
      else:
2072
4805aee792f0
        url_data = self._cache.Get(key)
2073
17f566981b41
2074
4805aee792f0
    # Always return the latest version
2075
4805aee792f0
    return url_data
2076
4805aee792f0
2077
81cef10d2991
2078
4805aee792f0
class _FileCacheError(Exception):
2079
4805aee792f0
  '''Base exception class for FileCache related errors'''
2080
4805aee792f0
2081
4805aee792f0
class _FileCache(object):
2082
17f566981b41
2083
4805aee792f0
  DEPTH = 3
2084
17f566981b41
2085
4805aee792f0
  def __init__(self,root_directory=None):
2086
4805aee792f0
    self._InitializeRootDirectory(root_directory)
2087
17f566981b41
2088
4805aee792f0
  def Get(self,key):
2089
4805aee792f0
    path = self._GetPath(key)
2090
4805aee792f0
    if os.path.exists(path):
2091
4805aee792f0
      return open(path).read()
2092
4805aee792f0
    else:
2093
4805aee792f0
      return None
2094
17f566981b41
2095
4805aee792f0
  def Set(self,key,data):
2096
4805aee792f0
    path = self._GetPath(key)
2097
4805aee792f0
    directory = os.path.dirname(path)
2098
4805aee792f0
    if not os.path.exists(directory):
2099
4805aee792f0
      os.makedirs(directory)
2100
4805aee792f0
    if not os.path.isdir(directory):
2101
4805aee792f0
      raise _FileCacheError('%s exists but is not a directory' % directory)
2102
4805aee792f0
    temp_fd, temp_path = tempfile.mkstemp()
2103
4805aee792f0
    temp_fp = os.fdopen(temp_fd, 'w')
2104
4805aee792f0
    temp_fp.write(data)
2105
4805aee792f0
    temp_fp.close()
2106
4805aee792f0
    if not path.startswith(self._root_directory):
2107
4805aee792f0
      raise _FileCacheError('%s does not appear to live under %s' %
2108
4805aee792f0
                            (path, self._root_directory))
2109
744e374963dc
    if os.path.exists(path):
2110
744e374963dc
      os.remove(path)
2111
4805aee792f0
    os.rename(temp_path, path)
2112
17f566981b41
2113
4805aee792f0
  def Remove(self,key):
2114
4805aee792f0
    path = self._GetPath(key)
2115
4805aee792f0
    if not path.startswith(self._root_directory):
2116
4805aee792f0
      raise _FileCacheError('%s does not appear to live under %s' %
2117
4805aee792f0
                            (path, self._root_directory ))
2118
4805aee792f0
    if os.path.exists(path):
2119
17f566981b41
      os.remove(path)
2120
17f566981b41
2121
4805aee792f0
  def GetCachedTime(self,key):
2122
4805aee792f0
    path = self._GetPath(key)
2123
4805aee792f0
    if os.path.exists(path):
2124
4805aee792f0
      return os.path.getmtime(path)
2125
4805aee792f0
    else:
2126
4805aee792f0
      return None
2127
17f566981b41
2128
795f1c9d49c9
  def _GetUsername(self):
2129
3bef9042269d
    '''Attempt to find the username in a cross-platform fashion.'''
2130
d981d739f261
    try:
2131
d981d739f261
      return os.getenv('USER') or \
2132
d981d739f261
             os.getenv('LOGNAME') or \
2133
d981d739f261
             os.getenv('USERNAME') or \
2134
d981d739f261
             os.getlogin() or \
2135
d981d739f261
             'nobody'
2136
fc7763723e15
    except (IOError, OSError), e:
2137
d981d739f261
      return 'nobody'
2138
795f1c9d49c9
2139
795f1c9d49c9
  def _GetTmpCachePath(self):
2140
795f1c9d49c9
    username = self._GetUsername()
2141
795f1c9d49c9
    cache_directory = 'python.cache_' + username
2142
795f1c9d49c9
    return os.path.join(tempfile.gettempdir(), cache_directory)
2143
795f1c9d49c9
2144
4805aee792f0
  def _InitializeRootDirectory(self, root_directory):
2145
4805aee792f0
    if not root_directory:
2146
795f1c9d49c9
      root_directory = self._GetTmpCachePath()
2147
4805aee792f0
    root_directory = os.path.abspath(root_directory)
2148
4805aee792f0
    if not os.path.exists(root_directory):
2149
4805aee792f0
      os.mkdir(root_directory)
2150
4805aee792f0
    if not os.path.isdir(root_directory):
2151
4805aee792f0
      raise _FileCacheError('%s exists but is not a directory' %
2152
4805aee792f0
                            root_directory)
2153
4805aee792f0
    self._root_directory = root_directory
2154
17f566981b41
2155
4805aee792f0
  def _GetPath(self,key):
2156
a58f4a7ad991
    try:
2157
a58f4a7ad991
        hashed_key = md5(key).hexdigest()
2158
a58f4a7ad991
    except TypeError:
2159
a58f4a7ad991
        hashed_key = md5.new(key).hexdigest()
2160
a58f4a7ad991
        
2161
4805aee792f0
    return os.path.join(self._root_directory,
2162
4805aee792f0
                        self._GetPrefix(hashed_key),
2163
4805aee792f0
                        hashed_key)
2164
17f566981b41
2165
4805aee792f0
  def _GetPrefix(self,hashed_key):
2166
4805aee792f0
    return os.path.sep.join(hashed_key[0:_FileCache.DEPTH])