Search code examples
pythonnamespacesextractgetattr

Misuse of dot-syntax for a convenient way to access an API in Python


I'd like to write an convenient interface for the flickr-API in Python. The methods provided by the API

flickr.galleries.addPhoto
flickr.galleries.create
flickr.cameras.getBrandModels
flickr.cameras.getBrands
etc.

are used in a normal http-request, like

http://api.flickr.com/services/rest/?method=flickr.X&param1=value1&param2=value2&param3&

My idea was to write a class flickr, which might enable me to call the methods in the same syntax in Python. So the class flickr, should enable me to access the identifier X=galleries.addPhoto when i call

flickr.X(param1=value1,param2=value2)

I thought about using the getattr function to use the function name as a parameter, but unfortunately i failed.

Is there a way to access the name of X ignoring the dots.

P.s. the class flickr should not check (or hold) the exact structure of the "namespaces" like galleries, camera, etc. to stay are generic as possible and not being affected as the names of methods will change in the future.


Solution

  • I don't know if I'd recommend stretching the python syntax so far but the getattr class method will work. It is invoked whenever you access a member that is not in a class's dictionary, so you need to be sure that "X" is not a class member, use something like "_X" instead and then use a class structure like this:

    class a(object):
        def _hi(self):
            print "hello"
    
        def __getattr__(self, val):
            a.__dict__["_" + val](self)
    
    >>> b = a() 
    >>> b.hi
    hello
    

    ***EDIT: dealing with the dot syntax

    class A(object):
        def __init__(self, call_tree=None):
            self.call_tree = call_tree
    
        def __getattr__(self, val):
            if self.call_tree:
                new_call_tree = '.'.join([self.call_tree, val])
            else:
                new_call_tree = val
            return A(call_tree=new_call_tree)
    
        def __call__(self, *args, **kwargs):
            url = 'https://api.flickr.com/?function={}'.format(self.call_tree)
            print url
    
    >>> b = A()
    >>> b.hi.mom()
    https://api.flickr.com/?function=hi.mom
    >>> b.hi.dad()
    https://api.flickr.com/?function=hi.dad