Skip to content
This repository was archived by the owner on Aug 7, 2024. It is now read-only.

Commit 9df6b6c

Browse files
committed
merge from master
2 parents 10877f6 + 14cc046 commit 9df6b6c

6 files changed

Lines changed: 265 additions & 39 deletions

File tree

CHANGES

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
2015-10-05
2+
Added who to api.GetSearch
3+
14
2014-12-29
25
removed reference to simplejson
36

twitter/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,7 @@
3838
from .url import Url
3939
from .status import Status
4040
from .user import User, UserStatus
41+
from .category import Category
42+
from .media import Media
4143
from .list import List
4244
from .api import Api

twitter/api.py

Lines changed: 71 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242

4343
from twitter import (__version__, _FileCache, json, DirectMessage, List,
4444
Status, Trend, TwitterError, User, UserStatus)
45+
from twitter.category import Category
4546

4647
try:
4748
# python 3
@@ -277,6 +278,7 @@ def ClearCredentials(self):
277278

278279
def GetSearch(self,
279280
term=None,
281+
who=None,
280282
geocode=None,
281283
since_id=None,
282284
max_id=None,
@@ -292,6 +294,8 @@ def GetSearch(self,
292294
Args:
293295
term:
294296
Term to search by. Optional if you include geocode.
297+
who:
298+
Handle of user's tweets you want. Optional.
295299
since_id:
296300
Returns results with an ID greater than (that is, more recent
297301
than) the specified ID. There are limits to the number of
@@ -350,7 +354,7 @@ def GetSearch(self,
350354

351355
if until:
352356
parameters['until'] = until
353-
357+
354358
if since:
355359
parameters['since'] = since
356360

@@ -360,12 +364,15 @@ def GetSearch(self,
360364
if locale:
361365
parameters['locale'] = locale
362366

363-
if term is None and geocode is None:
367+
if term is None and geocode is None and who is None:
364368
return []
365369

366370
if term is not None:
367371
parameters['q'] = term
368372

373+
if who is not None:
374+
parameters['q'] = "from:%s" % (who)
375+
369376
if geocode is not None:
370377
parameters['geocode'] = ','.join(map(str, geocode))
371378

@@ -479,6 +486,40 @@ def GetTrendsWoeid(self, id, exclude=None):
479486
trends.append(Trend.NewFromJsonDict(trend, timestamp=timestamp))
480487
return trends
481488

489+
def GetUserSuggestionCategories(self):
490+
""" Return the list of suggested user categories, this can be used in
491+
GetUserSuggestion function
492+
Returns:
493+
A list of categories
494+
"""
495+
url = '%s/users/suggestions.json' % (self.base_url)
496+
json_data = self._RequestUrl(url, verb='GET')
497+
data = self._ParseAndCheckTwitter(json_data.content)
498+
499+
categories = []
500+
501+
for category in data:
502+
categories.append(Category.NewFromJsonDict(category))
503+
return categories
504+
505+
def GetUserSuggestion(self, category):
506+
""" Returns a list of users in a category
507+
Args:
508+
category:
509+
The Category object to limit the search by
510+
Returns:
511+
A list of users in that category
512+
"""
513+
url = '%s/users/suggestions/%s.json' % (self.base_url, category.Slug)
514+
515+
json_data = self._RequestUrl(url, verb='GET')
516+
data = self._ParseAndCheckTwitter(json_data.content)
517+
518+
users = []
519+
for user in data['users']:
520+
users.append(User.NewFromJsonDict(user))
521+
return users
522+
482523
def GetHomeTimeline(self,
483524
count=None,
484525
since_id=None,
@@ -1585,12 +1626,12 @@ def GetFollowerIDsPaged(self,
15851626
if count is not None:
15861627
parameters['count'] = count
15871628
result = []
1588-
1629+
15891630
parameters['cursor'] = cursor
1590-
1631+
15911632
json = self._RequestUrl(url, 'GET', data=parameters)
15921633
data = self._ParseAndCheckTwitter(json.content)
1593-
1634+
15941635
if 'next_cursor' in data:
15951636
next_cursor = data['next_cursor']
15961637
else:
@@ -1599,7 +1640,7 @@ def GetFollowerIDsPaged(self,
15991640
previous_cursor = data['previous_cursor']
16001641
else:
16011642
previous_cursor = 0
1602-
1643+
16031644
return next_cursor, previous_cursor, data
16041645

16051646
def GetFollowerIDs(self,
@@ -1638,17 +1679,22 @@ def GetFollowerIDs(self,
16381679
url = '%s/followers/ids.json' % self.base_url
16391680
if not self.__auth:
16401681
raise TwitterError({'message': "twitter.Api instance must be authenticated"})
1641-
1682+
16421683
result = []
16431684
if total_count and total_count < count:
16441685
count = total_count
1645-
1686+
16461687
while True:
1688+
<<<<<<< HEAD
16471689
if total_count and total_count < count:
16481690
parameters['count'] = total_count
16491691
parameters['cursor'] = cursor
16501692
json = self._RequestUrl(url, 'GET', data=parameters)
16511693
data = self._ParseAndCheckTwitter(json.content.decode('utf-8').decode("utf-8"))
1694+
=======
1695+
next_cursor, previous_cursor, data = self.GetFollowerIDsPaged(user_id, screen_name, cursor, stringify_ids,
1696+
count)
1697+
>>>>>>> master
16521698
result += [x for x in data['ids']]
16531699
if next_cursor == 0 or next_cursor == previous_cursor:
16541700
break
@@ -1660,7 +1706,7 @@ def GetFollowerIDs(self,
16601706
break
16611707
sec = self.GetSleepTime('/followers/ids')
16621708
time.sleep(sec)
1663-
1709+
16641710
return result
16651711

16661712
def GetFollowersPaged(self,
@@ -2073,7 +2119,7 @@ def CreateFriendship(self, user_id=None, screen_name=None, follow=True):
20732119
A twitter.User instance representing the befriended user.
20742120
"""
20752121
return self._AddOrEditFriendship(user_id=user_id, screen_name=screen_name, follow=follow)
2076-
2122+
20772123
def _AddOrEditFriendship(self, user_id=None, screen_name=None, uri_end='create', follow_key='follow', follow=True):
20782124
"""
20792125
Shared method for Create/Update Friendship.
@@ -2114,7 +2160,8 @@ def UpdateFriendship(self, user_id=None, screen_name=None, follow=True, **kwargs
21142160
A twitter.User instance representing the befriended user.
21152161
"""
21162162
follow = kwargs.get('device', follow)
2117-
return self._AddOrEditFriendship(user_id=user_id, screen_name=screen_name, follow=follow, follow_key='device', uri_end='update')
2163+
return self._AddOrEditFriendship(user_id=user_id, screen_name=screen_name, follow=follow, follow_key='device',
2164+
uri_end='update')
21182165

21192166
def DestroyFriendship(self, user_id=None, screen_name=None):
21202167
"""Discontinues friendship with a user_id or screen_name.
@@ -2893,7 +2940,7 @@ def GetListTimeline(self,
28932940
"""
28942941
parameters = {'slug': slug,
28952942
'list_id': list_id,
2896-
}
2943+
}
28972944
url = '%s/lists/statuses.json' % (self.base_url)
28982945
parameters['slug'] = slug
28992946
parameters['list_id'] = list_id
@@ -2902,7 +2949,7 @@ def GetListTimeline(self,
29022949
raise TwitterError({'message': "list_id or slug required"})
29032950
if owner_id is None and not owner_screen_name:
29042951
raise TwitterError({
2905-
'message': "if list_id is not given you have to include an owner to help identify the proper list"})
2952+
'message': "if list_id is not given you have to include an owner to help identify the proper list"})
29062953
if owner_id:
29072954
parameters['owner_id'] = owner_id
29082955
if owner_screen_name:
@@ -2976,7 +3023,7 @@ def GetListMembers(self,
29763023
"""
29773024
parameters = {'slug': slug,
29783025
'list_id': list_id,
2979-
}
3026+
}
29803027
url = '%s/lists/members.json' % (self.base_url)
29813028
parameters['slug'] = slug
29823029
parameters['list_id'] = list_id
@@ -2985,7 +3032,7 @@ def GetListMembers(self,
29853032
raise TwitterError({'message': "list_id or slug required"})
29863033
if owner_id is None and not owner_screen_name:
29873034
raise TwitterError({
2988-
'message': "if list_id is not given you have to include an owner to help identify the proper list"})
3035+
'message': "if list_id is not given you have to include an owner to help identify the proper list"})
29893036
if owner_id:
29903037
parameters['owner_id'] = owner_id
29913038
if owner_screen_name:
@@ -3297,22 +3344,22 @@ def UpdateImage(self,
32973344

32983345
url = '%s/account/update_profile_image.json' % (self.base_url)
32993346
with open(image, 'rb') as image_file:
3300-
encoded_image = base64.b64encode(image_file.read())
3347+
encoded_image = base64.b64encode(image_file.read())
33013348
data = {
3302-
'image':encoded_image
3349+
'image': encoded_image
33033350
}
33043351
if include_entities:
3305-
data['include_entities'] = 1
3352+
data['include_entities'] = 1
33063353
if skip_status:
3307-
data['skip_status'] = 1
3354+
data['skip_status'] = 1
33083355

33093356
json = self._RequestUrl(url, 'POST', data=data)
33103357
if json.status_code in [200, 201, 202]:
3311-
return True
3358+
return True
33123359
if json.status_code == 400:
3313-
raise TwitterError({'message': "Image data could not be processed"})
3360+
raise TwitterError({'message': "Image data could not be processed"})
33143361
if json.status_code == 422:
3315-
raise TwitterError({'message': "The image could not be resized or is too large."})
3362+
raise TwitterError({'message': "The image could not be resized or is too large."})
33163363

33173364
def UpdateBanner(self,
33183365
image,
@@ -3833,15 +3880,15 @@ def _RequestStream(self, url, verb, data=None):
38333880
return requests.post(url, data=data, stream=True,
38343881
auth=self.__auth,
38353882
timeout=self._timeout
3836-
)
3883+
)
38373884
except requests.RequestException as e:
38383885
raise TwitterError(str(e))
38393886
if verb == 'GET':
38403887
url = self._BuildUrl(url, extra_params=data)
38413888
try:
38423889
return requests.get(url, stream=True, auth=self.__auth,
38433890
timeout=self._timeout
3844-
)
3891+
)
38453892
except requests.RequestException as e:
38463893
raise TwitterError(str(e))
38473894
return 0 # if not a POST or GET request

twitter/category.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#!/usr/bin/env python
2+
3+
4+
class Category(object):
5+
"""A class representing the suggested user category structure used by the twitter API.
6+
7+
The UserStatus structure exposes the following properties:
8+
9+
category.name
10+
category.slug
11+
category.size
12+
"""
13+
14+
def __init__(self, **kwargs):
15+
"""An object to hold a Twitter suggested user category .
16+
This class is normally instantiated by the twitter.Api class and
17+
returned in a sequence.
18+
19+
Args:
20+
name:
21+
name of the category
22+
slug:
23+
24+
size:
25+
"""
26+
param_defaults = {
27+
'name': None,
28+
'slug': None,
29+
'size': None,
30+
}
31+
32+
for (param, default) in param_defaults.iteritems():
33+
setattr(self, param, kwargs.get(param, default))
34+
35+
@property
36+
def Name(self):
37+
return self.name or False
38+
39+
@property
40+
def Slug(self):
41+
return self.slug or False
42+
43+
@property
44+
def Size(self):
45+
return self.size or False
46+
47+
@staticmethod
48+
def NewFromJsonDict(data):
49+
"""Create a new instance based on a JSON dict.
50+
51+
Args:
52+
data: A JSON dict, as converted from the JSON in the twitter API
53+
Returns:
54+
A twitter.Category instance
55+
"""
56+
57+
return Category(name=data.get('name', None),
58+
slug=data.get('slug', None),
59+
size=data.get('size', None))

0 commit comments

Comments
 (0)