python api

11 views
Skip to first unread message

Abhi

unread,
Jan 29, 2007, 8:17:53 AM1/29/07
to Remember The Milk API
Hey everyone,

I was bored so I wrote a Python class for accessing rmilk. The code is
a first revision so there may be bugs. If so please let me know.
Otherwise there are a few examples at the bottom and if the code is
unclear please let me know and I'll help. This code also uses xmltramp
so make sure you have that and all patches are welcome if you fix
something or make something look better. Thanks.
---

import md5
import urllib2
import webbrowser
import xmltramp

class RememberTheMilk:
def __init__(self, api, secret):
self.API = api
self.SECRET = secret
self.token = ''

def authenticate(self, perms='delete', auth_time=5):
tramp = xmltramp.parse(self.rtm_auth_getFrob())
frob = str(tramp.frob)

params = {}
params['frob'] = frob
params['api_key'] = self.API
params['perms'] = perms
params['api_sig'] = self.sign_request(params)

webbrowser.open_new('http://www.rememberthemilk.com/services/
auth/' + self.pretty_params(params))

import time
time.sleep(auth_time)

auth_xml = self.rtm_auth_getToken({'frob': params['frob']})
tramp = xmltramp.parse(auth_xml)
self.token = str(tramp.auth.token)

def pretty_params(self, params):
param_str = ''
first = False
for k, v in params.iteritems():
if first is False:
param_str += '?'
first = True
else:
param_str += '&'

param_str += k + '=' + v

return param_str

def sign_request(self, params):
''' Signs it according to:
http://www.rememberthemilk.com/services/api/
authentication.rtm
'''
keys = params.keys()
keys.sort()

sig_str = self.SECRET
for key in keys:
sig_str += key + params[key]

return md5.new(sig_str).hexdigest()

def make_request(self, method, params):
params['api_key'] = self.API
params['method'] = method

if self.token is not '':
params['auth_token'] = self.token

params['api_sig'] = self.sign_request(params)

url = 'http://www.rememberthemilk.com/services/rest/' +
self.pretty_params(params)
req = urllib2.urlopen(url)
return req.read()

def __getattr__(self, name):
if name:
return lambda params={}:
self.make_request(name.replace('_', '.'), params)
else:
raise AttributeError, name


rmilk = RememberTheMilk(API_KEY, SECRET)
rmilk.authenticate()
print rmilk.rtm_lists_getList()
tramp = xmltramp.parse(rmilk.rtm_timelines_create())
print rmilk.rtm_tasks_add({'list_id': '12345', 'name': 'Test',
'timeline': str(tramp.timeline)})

Peter Ruibal

unread,
Jan 30, 2007, 5:32:53 PM1/30/07
to remembert...@googlegroups.com
self.make_request (name.replace('_', '.'), params)

        else:
            raise AttributeError, name


rmilk = RememberTheMilk(API_KEY, SECRET)
rmilk.authenticate()
print rmilk.rtm_lists_getList()
tramp = xmltramp.parse(rmilk.rtm_timelines_create())
print rmilk.rtm_tasks_add({'list_id': '12345', 'name': 'Test',
'timeline': str(tramp.timeline)})


Updated http://ruibalweb.com/pyrtm/pyrtm.py for the following:

* Rate limited to 1 request per second (see http://www.rememberthemilk.com/services/api/ )
* Removed pretty_params()  in favor of urllib.urlencode

I'll have to look at the ToS before adding the ability to login/grant permission directly on the object.

--
Peter Ruibal

Abhi

unread,
Jan 30, 2007, 5:53:59 PM1/30/07
to Remember The Milk API
Sweet. I realized today I could have used urlencode instead of writing
my own method. Speaks a lot about my coding ability...

Abhi

On Jan 30, 2:32 pm, "Peter Ruibal" <ruib...@gmail.com> wrote:

> > self.make_request(name.replace('_', '.'), params)


> > else:
> > raise AttributeError, name
>
> > rmilk = RememberTheMilk(API_KEY, SECRET)
> > rmilk.authenticate()
> > print rmilk.rtm_lists_getList()
> > tramp = xmltramp.parse(rmilk.rtm_timelines_create())
> > print rmilk.rtm_tasks_add({'list_id': '12345', 'name': 'Test',
> > 'timeline': str(tramp.timeline)})
>

> Updatedhttp://ruibalweb.com/pyrtm/pyrtm.pyfor the following:

Abhi

unread,
Jan 31, 2007, 3:52:54 AM1/31/07
to Remember The Milk API
Act 3
---


"""pyrtm: Access Remember the Milk with Python."""

__version__ = "0.2"
__author__ = "ykabhinav"
__credits__ = "Contributions from ruibalp"
__copyright__ = "(C) 2007 ykabhinav."

import md5
import urllib2
import urllib
import webbrowser
import xmltramp
import time

class RememberTheMilk:
def __init__(self, api, secret):

'''api - the api developer key.
secret - the secret key you get with the api.'''
self.__API = api
self.__SECRET = secret
self.__token = ''
self.__time = 0

def authenticate(self, perms='delete', auth_time=5):

'''perms - choices include: read, write, delete.
auth_time - the number of second you give the user to
authenticate
the application.'''


tramp = xmltramp.parse(self.rtm_auth_getFrob())
frob = str(tramp.frob)

params = {}
params['frob'] = frob

params['api_key'] = self.__API
params['perms'] = perms
params['api_sig'] = self.__sign_request(params)

url = 'http://www.rememberthemilk.com/services/auth/?' +
urllib.urlencode(params)
webbrowser.open_new(url)
time.sleep(auth_time)

auth_xml = self.rtm_auth_getToken({'frob': params['frob']})
tramp = xmltramp.parse(auth_xml)

self.__token = str(tramp.auth.token)

def __sign_request(self, params):
'''params - all the parameters send to server.

Signs paramaters according to:


http://www.rememberthemilk.com/services/api/
authentication.rtm'''
keys = params.keys()
keys.sort()

sig_str = self.__SECRET


for key in keys:
sig_str += key + params[key]

return md5.new(sig_str).hexdigest()

def __make_request(self, method, params):
'''method - the api method we are calling.
params - the params that we are sending for the method.

Makes a request for the api method from rmilk. Also puts a
one second delay between calls.'''
params['api_key'] = self.__API
params['method'] = method

if self.__token is not '':
params['auth_token'] = self.__token

params['api_sig'] = self.__sign_request(params)

url = 'http://www.rememberthemilk.com/services/rest/?' +
urllib.urlencode(params)

atime = time.time() - self.__time;
if atime < 1:
atime = 1 - atime
time.sleep(atime)

req = urllib2.urlopen(url)
result = req.read();

print result
self.__time += atime;

return result

def __getattr__(self, name):
'''The magic.'''
def __func(params={}):
return self.__make_request(name.replace('_', '.'), params)

return __func

> > Updatedhttp://ruibalweb.com/pyrtm/pyrtm.pyforthe following:

Abhi

unread,
Jan 31, 2007, 3:56:49 AM1/31/07
to Remember The Milk API
Whoops... left a debugging doohickey there.
Act 4.
---

self.__token = str(tramp.auth.token)

return md5.new(sig_str).hexdigest()

params['api_sig'] = self.__sign_request(params)

self.__time += atime;

return result

def __getattr__(self, name):
'''The magic.'''
def __func(params={}):
return self.__make_request(name.replace('_', '.'), params)

return __func

Peter Ruibal

unread,
Jan 31, 2007, 5:54:47 PM1/31/07
to remembert...@googlegroups.com
I merged abhi's changes (version 0.2) into the file, and then added some more today.

(version 0.2-r1)
*   Token may be passed to the constructor in order to skip authentication.

(version 0.3)
*   Normalized tabbing to 4 spaces for each level (so you may want to diff -b)
*   RememberTheMilk.authenticate now doesn't depend on an external browser to authenticate, grant access to rtm (uhhhhhh...)

There's some mild hackery involved in the "autoallowsvc" parameter, and should probably be rewritten or removed, but hey, it's set to false by default!

Please see :
http://ruibalweb.com/pyrtm/versions/pyrtm-latest.py

--
Peter Ruibal

Abhi

unread,
Feb 13, 2007, 11:00:25 AM2/13/07
to Remember The Milk API
This is my final release. I removed the dependency on xmltramp so all
you need for this to work is the core python libraries. Also there is
a web authentication added on given with the unoriginal names
web_authenticate1 and web_authenticate2. Have fun.

"""pyrtm: Access Remember the Milk with Python."""

__version__ = "0.4"


__author__ = "ykabhinav"
__credits__ = "Contributions from ruibalp"
__copyright__ = "(C) 2007 ykabhinav."

import md5
import time
import urllib
import urllib2
import webbrowser
import xml.dom.minidom

class RememberTheMilk:
def __init__(self, api, secret, token=''):


'''api - the api developer key.
secret - the secret key you get with the api.'''
self.__API = api
self.__SECRET = secret
self.__token = ''
self.__time = 0

def web_authenticate1(self, perms='delete'):
dom = xml.dom.minidom.parseString(self.rtm_auth_getFrob())
frob = dom.getElementsByTagName('frob')[0].childNodes[0].data

params = {}


params['api_key'] = self.__API
params['perms'] = perms
params['api_sig'] = self.__sign_request(params)

url = 'http://www.rememberthemilk.com/services/auth/?' +
urllib.urlencode(params)

return url

def web_authenticate2(self, frob):
auth_xml = self.rtm_auth_getToken({'frob': frob})
dom = xml.dom.minidom.parseString(auth_xml)

self.__token = dom.getElementsByTagName('token')
[0].childNodes[0].data

def authenticate(self, type, perms='delete', auth_time=5):


'''perms - choices include: read, write, delete.
auth_time - the number of second you give the user to
authenticate
the application.'''

dom = xml.dom.minidom.parseString(self.rtm_auth_getFrob())
frob = dom.getElementsByTagName('frob')[0].childNodes[0].data

params = {}
params['frob'] = frob
params['api_key'] = self.__API
params['perms'] = perms
params['api_sig'] = self.__sign_request(params)

url = 'http://www.rememberthemilk.com/services/auth/?' +
urllib.urlencode(params)

webbrowser.open_new(url)
time.sleep(auth_time)

auth_xml = self.rtm_auth_getToken({'frob': params['frob']})

dom = xml.dom.minidom.parseString(auth_xml)

self.__token = dom.getElementsByTagName('token')
[0].childNodes[0].data

Reply all
Reply to author
Forward
0 new messages