~parinporecha/gtg/config_parser_bug

« back to all changes in this revision

Viewing changes to GTG/backends/rtm/rtm.py

  • Committer: Izidor Matušov
  • Date: 2013-02-25 07:35:07 UTC
  • Revision ID: izidor.matusov@gmail.com-20130225073507-vgts69uthx7z2run
PEP8ification by Nimit

Show diffs side-by-side

added added

removed removed

Lines of Context:
5
5
    'API',
6
6
    'createRTM',
7
7
    'set_log_level',
8
 
        )
 
8
)
9
9
 
10
10
 
11
11
import urllib
29
29
            _use_jsonlib = True
30
30
        except ImportError:
31
31
            pass
32
 
    
 
32
 
33
33
if not _use_jsonlib:
34
34
    Log.warning("simplejson module is not available, "
35
 
             "falling back to the internal JSON parser. "
36
 
             "Please consider installing the simplejson module from "
37
 
             "http://pypi.python.org/pypi/simplejson.")
 
35
                "falling back to the internal JSON parser. "
 
36
                "Please consider installing the simplejson module from "
 
37
                "http://pypi.python.org/pypi/simplejson.")
38
38
 
39
39
SERVICE_URL = 'http://api.rememberthemilk.com/services/rest/'
40
40
AUTH_SERVICE_URL = 'http://www.rememberthemilk.com/services/auth/'
41
41
 
42
42
 
43
 
class RTMError(Exception): pass
44
 
 
45
 
class RTMAPIError(RTMError): pass
 
43
class RTMError(Exception):
 
44
    pass
 
45
 
 
46
 
 
47
class RTMAPIError(RTMError):
 
48
    pass
 
49
 
46
50
 
47
51
class AuthStateMachine(object):
48
52
 
49
 
    class NoData(RTMError): pass
 
53
    class NoData(RTMError):
 
54
        pass
50
55
 
51
56
    def __init__(self, states):
52
57
        self.states = states
54
59
 
55
60
    def dataReceived(self, state, datum):
56
61
        if state not in self.states:
57
 
            error_string = _("Invalid state")+" <%s>" 
 
62
            error_string = _("Invalid state") + " <%s>"
58
63
 
59
 
            raise RTMError, error_string % state
 
64
            raise RTMError(error_string % state)
60
65
        self.data[state] = datum
61
66
 
62
67
    def get(self, state):
63
68
        if state in self.data:
64
69
            return self.data[state]
65
70
        else:
66
 
            raise AuthStateMachine.NoData, 'No data for <%s>' % state
 
71
            raise AuthStateMachine.NoData('No data for <%s>' % state)
67
72
 
68
73
 
69
74
class RTM(object):
83
88
 
84
89
    def _sign(self, params):
85
90
        "Sign the parameters with MD5 hash"
86
 
        pairs = ''.join(['%s%s' % (k,v) for k,v in sortedItems(params)])
87
 
        return md5(self.secret+pairs).hexdigest()
 
91
        pairs = ''.join(['%s%s' % (k, v) for k, v in sortedItems(params)])
 
92
        return md5(self.secret + pairs).hexdigest()
88
93
 
89
94
    def get(self, **params):
90
95
        "Get the XML response for the passed `params`."
94
99
 
95
100
        json_data = openURL(SERVICE_URL, params).read()
96
101
 
97
 
        #LOG.debug("JSON response: \n%s" % json)
 
102
        # LOG.debug("JSON response: \n%s" % json)
98
103
        if _use_jsonlib:
99
104
            data = dottedDict('ROOT', json.loads(json_data))
100
105
        else:
102
107
        rsp = data.rsp
103
108
 
104
109
        if rsp.stat == 'fail':
105
 
            raise RTMAPIError, 'API call failed - %s (%s)' % (
106
 
                rsp.err.msg, rsp.err.code)
 
110
            raise RTMAPIError('API call failed - %s (%s)' % (
 
111
                rsp.err.msg, rsp.err.code))
107
112
        else:
108
113
            return rsp
109
114
 
120
125
 
121
126
        params = {
122
127
            'api_key': self.apiKey,
123
 
            'perms'  : 'delete',
124
 
            'frob'   : frob
125
 
            }
 
128
            'perms': 'delete',
 
129
            'frob': frob
 
130
        }
126
131
        params['api_sig'] = self._sign(params)
127
132
        return AUTH_SERVICE_URL + '?' + urllib.urlencode(params)
128
133
 
132
137
        self.authInfo.dataReceived('token', rsp.auth.token)
133
138
        return rsp.auth.token
134
139
 
 
140
 
135
141
class RTMAPICategory:
136
142
    "See the `API` structure and `RTM.__init__`"
137
143
 
150
156
            return lambda **params: self.callMethod(
151
157
                aname, rargs, oargs, **params)
152
158
        else:
153
 
            raise AttributeError, 'No such attribute: %s' % attr
 
159
            raise AttributeError('No such attribute: %s' % attr)
154
160
 
155
161
    def callMethod(self, aname, rargs, oargs, **params):
156
162
        # Sanity checks
157
163
        for requiredArg in rargs:
158
164
            if requiredArg not in params:
159
 
                raise TypeError, 'Required parameter (%s) missing' % requiredArg
 
165
                raise TypeError(
 
166
                    'Required parameter (%s) missing' % requiredArg)
160
167
 
161
168
        for param in params:
162
169
            if param not in rargs + oargs:
167
174
                            **params)
168
175
 
169
176
 
170
 
 
171
177
# Utility functions
172
 
 
173
178
def sortedItems(dictionary):
174
179
    "Return a list of (key, value) sorted based on keys"
175
180
    keys = dictionary.keys()
177
182
    for key in keys:
178
183
        yield key, dictionary[key]
179
184
 
 
185
 
180
186
def openURL(url, queryArgs=None):
181
187
    if queryArgs:
182
188
        url = url + '?' + urllib.urlencode(queryArgs)
183
 
    #LOG.debug("URL> %s", url)
 
189
    # LOG.debug("URL> %s", url)
184
190
    return urllib.urlopen(url)
185
191
 
 
192
 
186
193
class dottedDict(object):
187
194
    """Make dictionary items accessible via the object-dot notation."""
188
195
 
198
205
                             for i, item in indexed(value)]
199
206
                setattr(self, key, value)
200
207
        else:
201
 
            raise ValueError, 'not a dict: %s' % dictionary
 
208
            raise ValueError('not a dict: %s' % dictionary)
202
209
 
203
210
    def __repr__(self):
204
211
        children = [c for c in dir(self) if not c.startswith('_')]
210
217
def safeEval(string):
211
218
    return eval(string, {}, {})
212
219
 
 
220
 
213
221
def dottedJSON(json):
214
222
    return dottedDict('ROOT', safeEval(json))
215
223
 
 
224
 
216
225
def indexed(seq):
217
226
    index = 0
218
227
    for item in seq:
223
232
# API spec
224
233
 
225
234
API = {
226
 
   'auth': {
227
 
       'checkToken':
228
 
           [('auth_token',), ()],
229
 
       'getFrob':
230
 
           [(), ()],
231
 
       'getToken':
232
 
           [('frob',), ()]
233
 
       },
 
235
    'auth': {
 
236
        'checkToken':
 
237
        [('auth_token',), ()],
 
238
        'getFrob':
 
239
        [(), ()],
 
240
        'getToken':
 
241
        [('frob',), ()]
 
242
    },
234
243
    'contacts': {
235
244
        'add':
236
 
            [('timeline', 'contact'), ()],
 
245
    [('timeline', 'contact'), ()],
237
246
        'delete':
238
 
            [('timeline', 'contact_id'), ()],
 
247
    [('timeline', 'contact_id'), ()],
239
248
        'getList':
240
 
            [(), ()]
241
 
        },
 
249
    [(), ()]
 
250
    },
242
251
    'groups': {
243
252
        'add':
244
 
            [('timeline', 'group'), ()],
 
253
    [('timeline', 'group'), ()],
245
254
        'addContact':
246
 
            [('timeline', 'group_id', 'contact_id'), ()],
 
255
    [('timeline', 'group_id', 'contact_id'), ()],
247
256
        'delete':
248
 
            [('timeline', 'group_id'), ()],
 
257
    [('timeline', 'group_id'), ()],
249
258
        'getList':
250
 
            [(), ()],
 
259
    [(), ()],
251
260
        'removeContact':
252
 
            [('timeline', 'group_id', 'contact_id'), ()],
253
 
        },
 
261
    [('timeline', 'group_id', 'contact_id'), ()],
 
262
    },
254
263
    'lists': {
255
264
        'add':
256
 
            [('timeline', 'name',), ('filter',)],
 
265
    [('timeline', 'name',), ('filter',)],
257
266
        'archive':
258
 
            [('timeline', 'list_id'), ()],
 
267
    [('timeline', 'list_id'), ()],
259
268
        'delete':
260
 
            [('timeline', 'list_id'), ()],
 
269
    [('timeline', 'list_id'), ()],
261
270
        'getList':
262
 
            [(), ()],
 
271
    [(), ()],
263
272
        'setDefaultList':
264
 
            [('timeline'), ('list_id')],
 
273
    [('timeline'), ('list_id')],
265
274
        'setName':
266
 
            [('timeline', 'list_id', 'name'), ()],
 
275
    [('timeline', 'list_id', 'name'), ()],
267
276
        'unarchive':
268
 
            [('timeline',), ('list_id',)]
269
 
        },
 
277
    [('timeline',), ('list_id',)]
 
278
    },
270
279
    'locations': {
271
280
        'getList':
272
 
            [(), ()]
273
 
        },
 
281
    [(), ()]
 
282
    },
274
283
    'reflection': {
275
284
        'getMethodInfo':
276
 
            [('methodName',), ()],
 
285
    [('methodName',), ()],
277
286
        'getMethods':
278
 
            [(), ()]
279
 
        },
 
287
    [(), ()]
 
288
    },
280
289
    'settings': {
281
290
        'getList':
282
 
            [(), ()]
283
 
        },
 
291
    [(), ()]
 
292
    },
284
293
    'tasks': {
285
294
        'add':
286
 
            [('timeline', 'name',), ('list_id', 'parse',)],
 
295
    [('timeline', 'name',), ('list_id', 'parse',)],
287
296
        'addTags':
288
 
            [('timeline', 'list_id', 'taskseries_id', 'task_id', 'tags'),
289
 
             ()],
 
297
    [('timeline', 'list_id', 'taskseries_id', 'task_id', 'tags'),
 
298
     ()],
290
299
        'complete':
291
 
            [('timeline', 'list_id', 'taskseries_id', 'task_id',), ()],
 
300
    [('timeline', 'list_id', 'taskseries_id', 'task_id',), ()],
292
301
        'delete':
293
 
            [('timeline', 'list_id', 'taskseries_id', 'task_id'), ()],
 
302
    [('timeline', 'list_id', 'taskseries_id', 'task_id'), ()],
294
303
        'getList':
295
 
            [(),
296
 
             ('list_id', 'filter', 'last_sync')],
 
304
    [(),
 
305
     ('list_id', 'filter', 'last_sync')],
297
306
        'movePriority':
298
 
            [('timeline', 'list_id', 'taskseries_id', 'task_id', 'direction'),
299
 
             ()],
 
307
    [('timeline', 'list_id', 'taskseries_id', 'task_id', 'direction'),
 
308
     ()],
300
309
        'moveTo':
301
 
            [('timeline', 'from_list_id', 'to_list_id', 'taskseries_id', 'task_id'),
302
 
             ()],
 
310
    [(
 
311
    'timeline', 'from_list_id', 'to_list_id', 'taskseries_id', 'task_id'),
 
312
        ()],
303
313
        'postpone':
304
 
            [('timeline', 'list_id', 'taskseries_id', 'task_id'),
305
 
             ()],
 
314
        [('timeline', 'list_id', 'taskseries_id', 'task_id'),
 
315
         ()],
306
316
        'removeTags':
307
 
            [('timeline', 'list_id', 'taskseries_id', 'task_id', 'tags'),
308
 
             ()],
 
317
        [('timeline', 'list_id', 'taskseries_id', 'task_id', 'tags'),
 
318
         ()],
309
319
        'setDueDate':
310
 
            [('timeline', 'list_id', 'taskseries_id', 'task_id'),
311
 
             ('due', 'has_due_time', 'parse')],
 
320
        [('timeline', 'list_id', 'taskseries_id', 'task_id'),
 
321
         ('due', 'has_due_time', 'parse')],
312
322
        'setEstimate':
313
 
            [('timeline', 'list_id', 'taskseries_id', 'task_id'),
314
 
             ('estimate',)],
 
323
        [('timeline', 'list_id', 'taskseries_id', 'task_id'),
 
324
         ('estimate',)],
315
325
        'setLocation':
316
 
            [('timeline', 'list_id', 'taskseries_id', 'task_id'),
317
 
             ('location_id',)],
 
326
        [('timeline', 'list_id', 'taskseries_id', 'task_id'),
 
327
         ('location_id',)],
318
328
        'setName':
319
 
            [('timeline', 'list_id', 'taskseries_id', 'task_id', 'name'),
320
 
             ()],
 
329
        [('timeline', 'list_id', 'taskseries_id', 'task_id', 'name'),
 
330
         ()],
321
331
        'setPriority':
322
 
            [('timeline', 'list_id', 'taskseries_id', 'task_id'),
323
 
             ('priority',)],
 
332
        [('timeline', 'list_id', 'taskseries_id', 'task_id'),
 
333
         ('priority',)],
324
334
        'setRecurrence':
325
 
            [('timeline', 'list_id', 'taskseries_id', 'task_id'),
326
 
             ('repeat',)],
 
335
        [('timeline', 'list_id', 'taskseries_id', 'task_id'),
 
336
         ('repeat',)],
327
337
        'setTags':
328
 
            [('timeline', 'list_id', 'taskseries_id', 'task_id'),
329
 
             ('tags',)],
 
338
        [('timeline', 'list_id', 'taskseries_id', 'task_id'),
 
339
         ('tags',)],
330
340
        'setURL':
331
 
            [('timeline', 'list_id', 'taskseries_id', 'task_id'),
332
 
             ('url',)],
 
341
        [('timeline', 'list_id', 'taskseries_id', 'task_id'),
 
342
         ('url',)],
333
343
        'uncomplete':
334
 
            [('timeline', 'list_id', 'taskseries_id', 'task_id'),
335
 
             ()],
336
 
        },
 
344
        [('timeline', 'list_id', 'taskseries_id', 'task_id'),
 
345
         ()],
 
346
    },
337
347
    'tasksNotes': {
338
348
        'add':
339
 
            [('timeline', 'list_id', 'taskseries_id', 'task_id', 'note_title', 'note_text'), ()],
 
349
    [('timeline', 'list_id', 'taskseries_id',
 
350
      'task_id', 'note_title', 'note_text'), ()],
340
351
        'delete':
341
 
            [('timeline', 'note_id'), ()],
 
352
    [('timeline', 'note_id'), ()],
342
353
        'edit':
343
 
            [('timeline', 'note_id', 'note_title', 'note_text'), ()]
344
 
        },
 
354
    [('timeline', 'note_id', 'note_title', 'note_text'), ()]
 
355
    },
345
356
    'test': {
346
357
        'echo':
347
 
            [(), ()],
 
358
    [(), ()],
348
359
        'login':
349
 
            [(), ()]
350
 
        },
 
360
    [(), ()]
 
361
    },
351
362
    'time': {
352
363
        'convert':
353
 
            [('to_timezone',), ('from_timezone', 'to_timezone', 'time')],
 
364
    [('to_timezone',), ('from_timezone', 'to_timezone', 'time')],
354
365
        'parse':
355
 
            [('text',), ('timezone', 'dateformat')]
356
 
        },
 
366
    [('text',), ('timezone', 'dateformat')]
 
367
    },
357
368
    'timelines': {
358
369
        'create':
359
 
            [(), ()]
360
 
        },
 
370
    [(), ()]
 
371
    },
361
372
    'timezones': {
362
373
        'getList':
363
 
            [(), ()]
364
 
        },
 
374
    [(), ()]
 
375
    },
365
376
    'transactions': {
366
377
        'undo':
367
 
            [('timeline', 'transaction_id'), ()]
368
 
        },
369
 
    }
 
378
    [('timeline', 'transaction_id'), ()]
 
379
    },
 
380
}
 
381
 
370
382
 
371
383
def createRTM(apiKey, secret, token=None):
372
384
    rtm = RTM(apiKey, secret, token)
378
390
 
379
391
    return rtm
380
392
 
 
393
 
381
394
def test(apiKey, secret, token=None):
382
395
    rtm = createRTM(apiKey, secret, token)
383
396
 
389
402
    # print rspLists.lists.list
390
403
    print [(x.name, x.id) for x in rspLists.lists.list]
391
404
 
 
405
 
392
406
def set_log_level(level):
393
407
    '''Sets the log level of the logger used by the module.
394
 
    
 
408
 
395
409
    >>> import rtm
396
410
    >>> import logging
397
411
    >>> rtm.set_log_level(logging.INFO)
398
412
    '''
399
 
    
400
 
    #LOG.setLevel(level)
 
413
 
 
414
    # LOG.setLevel(level)