A new Python library for Flickr
Python
Switch branches/tags
Nothing to show
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
README.html
flipy.py
lgpl.txt

README.html

<html>
  <head>
    <title>Flipy - a simple Flickr API wrapper for Python</title>
    <script type="text/javascript" src="http://ianloic.com/wp-content/plugins/google_code_prettify/prettify.js"></script>
    <link rel="stylesheet" type="text/css" href="http://ianloic.com/wp-content/plugins/google_code_prettify/prettify.css">
    <style type="text/css">
      body {
        font-family: sans-serif;
      }
      .prettyprint {
        background-color: #eee;
        border: 1px solid #ccc !important;
      }
/*
      dt {
        font-style: italic;
      }
*/
    </style>
  </head>
  <body onload="prettyPrint()">
    <h1>Flipy - a simple Flickr API wrapper for Python</h1>

    <p>Flipy is a new, simple <a href="http://www.python.org">Python</a> library for accessing the <a href="http://www.flickr.com/services/api">Flickr API</a>. 
    The goal is to expose Flickr's API methods as-is, but for the responses to be as pythonic as possible.</p>

    <p>Flipy is licensed under the <a href="http://www.gnu.org/licenses/lgpl.html">GNU LGPL</a> which means pretty much anyone should be able to use it for whatever. If you're having problems with the licensing <a href="mailto:ian@mckellar.org">let me know</a>. Flipy is maintianed on <a href="http://github.com/ianloic/flipy">github</a>.

    <p>A basic use of the library is something like this:
<pre class="prettyprint">
from flipy import Flipy
flickr = Flipy(MY_API_KEY)
me = flickr.people.findByUsername(username='ianloic')
me_info = flickr.people.getInfo(user_id=me.nsid)
print 'My name is %s. I have %s photos at %s.' % (me_info.realname, me_info.photos.count, me_info.photosurl)
</pre>
    </p>

    <p>As you can see the method calls you make from Python exactly match Flickr's API documentation, but the objects returned obey Python conventions.</p>

    <h2>Requests</h2>

    <p>By convention you call your <code class="prettyprint">Flipy()</code> instance <code class="prettyprint">flickr</code>. Then you can call methods with the names described in Flickr's API documentation. Since Flickr takes named arguments, all arguments to must be passed by name.</p>

    <h3>Signed Requests</h3>

    <p>Requests will be signed if you supply an API secret, either as the second argument to the <code class="prettyprint">Flipy()</code> constructor or by setting the <code class="prettyprint">secret</code> field on your Flipy object. For example:
<pre class="prettyprint">
# this works
flickr = Flipy(MY_API_KEY)
flickr.secret = MY_API_SECRET
# so does this
flickr = Flipy(MY_API_KEY, MY_API_SECRET)
</pre>
    </p>

    <h3>Authenticated Requests</h3>

    <p>To authenticate, just use the normal Flickr API authentication calls. Flipy supports web, desktop and mobile because it simply wraps the existing API. If a Flipy object knows about the an auth token then it will be passed with all requests. The token can be assigned to the <code class="prettyprint">token</code> field on the Flipy object or passed into the constructor. There's also a helper method on the Flipy object, <code class="prettyprint">authurl</code> to return a signed authentication url. A desktop auth flow might look like:
<pre class="prettyprint">
flickr = Flipy(MY_API_KEY, MY_API_SECRET)
frob = flickr.auth.getFrob()
print 'Go to: %s' % flickr.authurl(perms='read', frob=frob)
raw_input("Press enter when you've completed your Flickr auth flow...")
token_response = flickr.auth.getToken(frob=frob)
flickr.token = token_response.token
# now you can make authenticated requests
</pre>
    </p>

    <h2>Responses</h2>

    <p>Response objects are mapped in a fairly simple, predictable manner. The outer &lt;rsp&gt; isn't present in Flipy's result objects. If there's an error you'll get an exception, currently not a very useful one, but that'll get better in the future. If there's no error you'll get either the root of the result (for most methods) or a list of the roots (if there more than one, such as for <code class="prettyprint">flickr.reflection.getMethodInfo</code>).</p>

    <p>For each XML node in the result there's a Python object. If the node has no attributes or child nodes then it will just be a string of its text value. All node attributes are represented as properties. If a node name is a plural (eg: &lt;photos&gt;) and similar but non-plural children (eg: &lt;photo&gt;) will be represented as items - ie: you can iterate over the node. Other child nodes are represented as properties. Some responses contain multiple children with the same name, but don't match the simple plural/singular naming, in that case the property will be an array of all of the values. If there are unexpected name conflicts an exception will be thrown, if you see that please report it and I'll update the code to handle the case.</p>

    <h2>Errors</h2>
    
    <p>If Flickr returns an error then a FlipyFlickrError will be thrown whose value is the error string from Flickr.</p>

    <h2>API</h2>

    <p>Apart from the request and reponse conventions described above, Flipy provides a small API of its own for your convenience.</p>

    <h3>Flipy object</h3>
    <p>The Flipy constructor takes an API key, an optional API secret and an optional auth token.
<pre class="prettyprint">
flickr = Flipy(API_KEY, [API_SECRET, [AUTH_TOKEN]])
</pre>
    The secret and auth token can be set later on fields on the instance:
<pre class="prettyprint">
flickr.secret = API_SECRET
flickr.token = AUTH_TOKEN
</pre>
</p>
    <p>There are methods to get various kinds of request URL, but users of the API shouldn't ever need to call them. They handle signing automatically.
<pre class="prettyprint">
flickr.resturl(method='flickr.my.method', foo='bar', baz='fuz')
flickr.authurl(frob='frob')
</pre>
</p>

    <h3>Method objects</h3>

    <p>Some Flickr API methods (such as <code class="prettyprint">flickr.photos.search</code>) paginate their results. You need to make multiple calls to the server to get all of the results. For methods such as this you can call <code class="prettyprint">paginate()</code> on the method to get a generator that will return all of the results. For example:
<pre class="prettyprint">
for photo in flickr.photos.search.paginate(user_id='76722295@N00'):
  print photo.id
</pre>
</p>

    <h3>Response objects</h3>

    <p>All response objects have a <code class="prettyprint">response.pprint()</code> method that can be used to print a relatively human readable version of their structure. It's useful when trying to work out how to get the information you want out.</p>

    <p>Some response objects have extra methods to make the API feel a little more object-oriented. I've only added a few but if you can think of more that make sense that you would like then please let me know.</p>

    <h4>&lt;photo&gt;, &lt;prevphoto&gt;, &lt;nextphoto&gt;</h4>
    <p><code class="prettyprint">photo.info()</code> return the full information about the photo. It calls <code class="prettyprint">flickr.photos.getInfo</code>.</p>
    <p><code class="prettyprint">photo.people()</code> return the people in the photo. It calls <code class="prettyprint">flickr.photos.people.getList</code>.</p>

    <h4>&lt;user&gt;</h4>
    <p><code class="prettyprint">user.photos()</code> return all photos uploaded by the user. It calls <code class="prettyprint">flickr.photos.search</code> internally so you can pass any appropriate additional parameters</p>
    <p><code class="prettyprint">user.photosOf()</code> return all photos of the user. It calls <code class="prettyprint">flickr.people.getPhotosOf</code> internally so you can pass any appropriate additional parameters</p>

    <h2>Extending</h2>

    <p>Flipy's method and response handling can be extended by supplying custom classes (or methods). To provide a custom response wrapper for the response elements named &lt;foo&gt; that adds a method just:
<pre class="prettyprint">
from flipy import Response
@Response.custom('foo')
class FooResponse(Response):
  def myMethod(self):
    print 'this is my custom method'
</pre>
This is how custom response objects are implemented. There are a bunch of examples of this in flipy.py.
</p>

    <h2>Future Plans</h2>

    <ul>
      <li>Support uploading</li>
      <li>Unit tests</li>
      <li>Verify unicode support</li>
      <li>Asynchronous operation</li>
      <li>Support different HTTP libraries</li>
    </ul>

  </body>
</html>