5
\$\begingroup\$

I wrote this, which essentially acts as a single library for all possible REST services.

Here is the main file, as of alpha version 1:

import requests, json

class RestConsumer(object):

    def __init__(self,base_url,append_json=False,**kwargs):
        self.base_url = base_url
        self.uriparts = []
        self.append_json = append_json
        self.kwargs = kwargs

    def __getattr__(self,k):
        if k=='spc':
            return self.spc
        if not k[0] == '_':
            self.uriparts.append(k)
        else:
            if k[1:3]=='in':
                self.uriparts.append(k[3:])
            elif k[1:3] == 'uh':
                self.uriparts.append(k.replace('_','-'))
        return self

    def spc(self,k):
        self.uriparts.append(k)
        return self

    def __call__(self, **kwargs):
        uri_constructed = '/'.join(self.uriparts)
        self.uriparts = []
        self.uri_constructed = "%s%s"%(uri_constructed,'.json') if self.append_json else uri_constructed
        self.url = '/'.join([self.base_url,self.uri_constructed])
        return self.get(self.url,**kwargs)

    def get(self,url,**kwargs):
        print url
        r = requests.get(url,**kwargs)
        return json.loads(r.content)

    def post(self,**kwargs):
        r = requests.post(**kwargs)
        return json.loads(r.content)

if __name__=='__main__':
    from pprint import pprint
    t = RestConsumer(base_url='https://api.twitter.com/1',append_json=True)
    public_timeline = t.statuses.public_timeline()
    pprint(public_timeline)

    g = RestConsumer(base_url='https://api.github.com')
    repos = g.users.kennethreitz.repos()
    pprint(repos)

    s = RestConsumer(base_url='http://api.stackoverflow.com/1.1')
    sr = s.users.spc('55562').questions.unanswered()
    pprint(sr)

    sr2 = s.tags.python.spc('top-answerers').spc('all-time')()
    pprint(sr2)

The rationale and usage is all explained in the README.

Please critique the library, the idea, implementation and shed light on alternatives.

\$\endgroup\$

2 Answers 2

4
\$\begingroup\$
import requests, json

class RestConsumer(object):

    def __init__(self,base_url,append_json=False,**kwargs):
        self.base_url = base_url
        self.uriparts = []
        self.append_json = append_json
        self.kwargs = kwargs

Since you treat attributes "special", I recommend putting _ in front of these attributes so that are clearly offset.

    def __getattr__(self,k):

I recommend not using the random letter k for the name.

        if k=='spc':
            return self.spc

__getattr__ only gets invoked if the attribute cannot be found. Since spc will be found this won't ever get used.

        if not k[0] == '_':
            self.uriparts.append(k)
        else:
            if k[1:3]=='in':
                self.uriparts.append(k[3:])

What's the point of this rule? _infoo means foo?

            elif k[1:3] == 'uh':
                self.uriparts.append(k.replace('_','-'))

uh?

        return self

I don't like the way you've implemented this. Accessing attributes modifying the object's state is deeply counter-intuitive.

    def spc(self,k):
        self.uriparts.append(k)
        return self

spc is not a clear name. Its hard to guess what it means.

    def __call__(self, **kwargs):
        uri_constructed = '/'.join(self.uriparts)
        self.uriparts = []
        self.uri_constructed = "%s%s"%(uri_constructed,'.json') if self.append_json else uri_constructed
        self.url = '/'.join([self.base_url,self.uri_constructed])
        return self.get(self.url,**kwargs)

    def get(self,url,**kwargs):
        print url
        r = requests.get(url,**kwargs)
        return json.loads(r.content)

    def post(self,**kwargs):
        r = requests.post(**kwargs)
        return json.loads(r.content)

get prints while post doesn't. Probably neither should be printing, a log facility might be useful.

The way you've designed this, some useful things won't work:

public_timeline = twitter.statuses.public_timeline
while True:
      print public_timeline()

or

user = s.users.spc(55562)
print user.questions.unanswered()
print user.questions.answered()

I suggest that instead of modifying the object, you return new objects. That way it will work in an intuitive manner.

Instead of spc I suggest that you provide a __getitem__. That way you can do:

 s.users[55562].questions.unanswered()

Which I think will make it cleaner.

\$\endgroup\$
2
  • \$\begingroup\$ All excellent feedback. Thank you. I am modifying it now. \$\endgroup\$
    – lprsd
    Commented Jan 31, 2012 at 6:47
  • \$\begingroup\$ I changed it from mutating self to returning new objects. But can't figure out how to enable the last useful things you talk about. stackoverflow.com/questions/9076403/… \$\endgroup\$
    – lprsd
    Commented Jan 31, 2012 at 8:37
1
\$\begingroup\$

you should include a docstring on what the program is (steal from readme "RestConsumer is a generic python wrapper for consuming JSON REST APIs" although maybe add alittle more on use).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.