ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/dtflickr/trunk/dtflickr/__init__.py
Revision: 52
Committed: 2011-01-23T04:15:25-08:00 (8 years, 3 months ago) by douglas
File size: 7999 byte(s)
Log Message:
Use new style classes and maybe add some new methods?

Line File contents
1 # DT Flickr
2 #
3 # Douglas Thrift
4 #
5 # $Id$
6
7 # Copyright 2008 Douglas Thrift
8 #
9 # Licensed under the Apache License, Version 2.0 (the "License");
10 # you may not use this file except in compliance with the License.
11 # You may obtain a copy of the License at
12 #
13 # http://www.apache.org/licenses/LICENSE-2.0
14 #
15 # Unless required by applicable law or agreed to in writing, software
16 # distributed under the License is distributed on an "AS IS" BASIS,
17 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 # See the License for the specific language governing permissions and
19 # limitations under the License.
20
21 import hashlib
22 import _methods
23 import re
24 import time
25 import urllib, urllib2
26
27 try:
28 import simplejson as json
29 except ImportError:
30 import json
31
32 class Failure(Exception):
33 def __init__(self, response):
34 self.__message = str(response.code) + ': ' + response.message
35
36 def __str__(self):
37 return self.__message
38
39 class _Namespace(object):
40 def __init__(self, flickr, namespace):
41 self.__flickr = flickr
42 self.__namespace = namespace
43
44 def _execute(self, method, **arguments):
45 return self.__flickr._execute(self.__namespace + '.' + method, **arguments)
46
47 for namespace, methods in _methods.namespaces:
48 code = 'class ' + _methods.namespace(namespace) + '(_Namespace):\n """flickr.' + namespace + '"""\n def __init__(self, flickr):\n _Namespace.__init__(self, flickr, \'' + namespace + '\')\n'
49
50 for method, documentation in methods:
51 code += ' def ' + method + '(self, **arguments):\n ' + repr(documentation) + '\n return self._execute(\'' + method + '\', **arguments)\n'
52
53 exec code in globals(), locals()
54
55 del namespace, methods, method, documentation, code
56
57 class Flickr(object):
58 """Usage Example:
59
60 import dtflickr
61
62 flickr = dtflickr.Flickr(api_key)
63 response = flickr.urls.getUserPhotos(user_id = '22264298@N00')
64
65 print response.user.url
66
67 # Output:
68 #
69 # http://www.flickr.com/photos/douglaswth/
70 """
71
72 def __init__(self, api_key, secret = None):
73 """dtflickr.Flickr
74
75 Flickr API
76
77 Arguments:
78
79 api_key (Required)
80 Your API application key.
81
82 secret (Optional)
83 Your secret for signing.
84 """
85 self.__api_key = api_key
86
87 if secret is not None:
88 self.__signature = hashlib.md5()
89
90 self.__signature.update(secret)
91 else:
92 self.__signature = None
93
94 for namespace, methods in _methods.namespaces:
95 exec 'self.' + namespace + ' = ' + _methods.namespace(namespace) + '(self)'
96
97 self.__cache = {}
98
99 def _execute(self, method, **arguments):
100 for name, value in arguments.iteritems():
101 arguments[name] = unicode(value).encode('utf8')
102
103 arguments['api_key'] = self.__api_key
104 arguments['format'] = 'json'
105 arguments['method'] = 'flickr.' + method
106 arguments['nojsoncallback'] = 1
107 parameters = arguments.items()
108
109 parameters.sort()
110
111 if self.__signature is not None:
112 signature = self.__signature.copy()
113
114 for name, value in parameters:
115 signature.update(name + unicode(value).encode('utf8'))
116
117 parameters.append(('api_sig', signature.hexdigest()))
118
119 parameters = urllib.urlencode(parameters)
120 cached = self.__cache.get(parameters)
121
122 if cached is not None and cached[0] > time.time():
123 response = cached[1]
124 now = time.time()
125
126 for parameters, cached in self.__cache.items():
127 if cached[0] <= now:
128 del self.__cache[parameters]
129
130 return response
131
132 response = json.load(urllib2.urlopen('http://api.flickr.com/services/rest/', parameters), object_hook = Response)
133
134 if response.stat == 'ok':
135 self.__cache[parameters] = (time.time() + 60, response)
136
137 return response
138 else:
139 raise Failure, response
140
141 class Response(object):
142 def __init__(self, data):
143 self.__data = data
144
145 def __repr__(self):
146 return str(self.__class__) + '(' + repr(self.__data) + ')'
147
148 def __str__(self):
149 return self.__data.get('_content', repr(self))
150
151 def __getattr__(self, name):
152 return self.__getitem__(name)
153
154 def __len__(self):
155 return len(self.__data)
156
157 def __getitem__(self, name):
158 return self.__data[name]
159
160 def __iter__(self):
161 return self.__data.iteritems()
162
163 def __contains__(self, name):
164 return name in self.__data
165
166 SmallSquare = 's'
167 Thumbnail = 't'
168 Small = 'm'
169 Medium = None
170 Large = 'b'
171 Original = 'o'
172
173 def getPhotoSourceURL(photo, size = Medium):
174 """Returns a photo source URL.
175
176 Arguments:
177
178 photo (Required)
179 A photo response.
180
181 size (Optional)
182 A size constant (SmallSquare, Thumbnail, Small, Medium (default), Large, or Original).
183 """
184 assert isinstance(photo, Response)
185
186 url = 'http://farm' + str(photo.farm) + '.static.flickr.com/' + str(photo.server) + '/' + str(photo.id) + '_'
187
188 if size != 'o':
189 url += photo.secret
190
191 if size is not None:
192 assert size in ['s', 't', 'm', 'b']
193
194 url += '_' + size
195
196 url += '.jpg'
197 else:
198 url += photo.originalsecret + '_o.' + photo.originalformat
199
200 return url
201
202 def getWebPageProfileURL(user_id):
203 """Returns a web page profile URL of a user.
204
205 Arguments:
206
207 user_id (Required):
208 The NSID or username of the user.
209 """
210 return __getWebPageURL() + 'people/' + user_id + '/'
211
212 def getWebPagePhotostreamURL(user_id):
213 """Returns a web page photostream URL of a user.
214
215 Arguments:
216
217 user_id (Required)
218 The NSID or username of the user.
219 """
220 return __getWebPageURL() + 'photos/' + user_id + '/'
221
222 def getBuddyiconURL(person, flickr = None):
223 """Returns a buddyicon URL for a person.
224
225 Arguments:
226
227 person (Required)
228 A person response or (if the flickr argument is specified) an NSID of the user.
229
230 flickr (Optional)
231 A Flickr API instance used to get a person response.
232 """
233 if isinstance(person, basestring):
234 assert flickr is not None and isinstance(flickr, Flickr)
235
236 person = flickr.people.getInfo(user_id = person).person
237
238 if int(person.iconserver) > 0:
239 return 'http://farm' + str(person.iconfarm) + '.static.flickr.com/' + str(person.iconserver) + '/buddyicons/' + person.nsid + '.jpg'
240 else:
241 return 'http://www.flickr.com/images/buddyicon.jpg'
242
243 def __getWebPageURL():
244 return 'http://www.flickr.com/'
245
246 __PhotoSourceURL = re.compile(r'^http://farm([0-9]+)\.static\.flickr\.com/([0-9]+)/([0-9]+)_([a-z0-9]+)(?:(?:_([bmst]))?\.jpg|_o\.(gif|jpg|png))(?:\?.*)?$')
247 __WebPageURL = re.compile(r'^http://(?:www\.)?flickr\.com/(?:people|photos)/([^/]+)(?:/(?:([0-9]+)(?:/in/(?:photostream|set-([0-9]+)))?|sets(?:/([0-9]+))?))?/?(?:\?.*)?$')
248 __BuddyiconURL = re.compile(r'^http://farm([0-9]+)\.static\.flickr\.com/([0-9]+)/buddyicons/([^/]+)\.jpg(?:\?.*)?$')
249
250 def getURLDetails(url):
251 """Parses a Flickr URL and returns useful information from it or None if it is not a useful URL.
252
253 This can currently parse photo source, user profile, user photos, photo, set, and buddyicon URLs.
254
255 Arguments:
256 url (Required)
257 A Flickr URL.
258 """
259 match = __PhotoSourceURL.match(url)
260
261 if match is not None:
262 if match.lastindex == 4:
263 return Response({'farm': match.group(1), 'server': match.group(2), 'photo': match.group(3), 'secret': match.group(4), 'size': Medium})
264 elif match.lastindex == 5:
265 return Response({'farm': match.group(1), 'server': match.group(2), 'photo': match.group(3), 'secret': match.group(4), 'size': match.group(5)})
266 elif match.lastindex == 6:
267 return Response({'farm': match.group(1), 'server': match.group(2), 'photo': match.group(3), 'originalsecret': match.group(4), 'size': Original, 'originalformat': match.group(6)})
268
269 match = __WebPageURL.match(url)
270
271 if match is not None:
272 if match.lastindex == 1:
273 return Response({'user': match.group(1)})
274 elif match.lastindex == 2:
275 return Response({'user': match.group(1), 'photo': match.group(2)})
276 elif match.lastindex == 3:
277 return Response({'user': match.group(1), 'photo': match.group(2), 'photoset': match.group(3)})
278 elif match.lastindex == 4:
279 return Response({'user': match.group(1), 'photoset': match.group(3)})
280
281 match = __BuddyiconURL.match(url)
282
283 if match is not None:
284 return Response({'iconfarm': match.group(1), 'iconserver': match.group(2), 'nsid': match.group(3)})
285
286 return None

Properties

Name Value
svn:keywords Id