From 1251cfb4400eee0116d92cb9c41efc4c08a72c84 Mon Sep 17 00:00:00 2001 From: Google Code Exporter Date: Tue, 26 Jan 2016 15:33:59 -0500 Subject: [PATCH] Migrating wiki contents from Google Code --- ProjectHome.md | 44 ++++++++++ Tutorial.md | 200 ++++++++++++++++++++++++++++++++++++++++++ WhytheNewObjectAPI.md | 59 +++++++++++++ 3 files changed, 303 insertions(+) create mode 100644 ProjectHome.md create mode 100644 Tutorial.md create mode 100644 WhytheNewObjectAPI.md diff --git a/ProjectHome.md b/ProjectHome.md new file mode 100644 index 0000000..d2ec0f2 --- /dev/null +++ b/ProjectHome.md @@ -0,0 +1,44 @@ +As complete as possible implementation of Flickr API. + +The project provides an almost exhaustive access to the Flickr API, through an **object oriented** Python interface. + +The project is still at an early stage and requires a lot of testing. +Any help including bug reports is appreciated. + +Main features : + * Object Oriented implementation + * (Almost) comprehensive implementation + * uses OAuth for authentication + * context sensitive objects (depending on the query context, objects may exhibit different attributes) + * An interface for direct seamless calls to the Flickr API. + * A (django-complient) caching mechanism + +requires: + * python 2.6+ + * python-oauth (or the python module from http://code.google.com/p/oauth/) + + +**The development activity has moved to GitHub**. You can download the development version from GitHub with: +``` +git clone git://github.com/alexis-mignon/python-flickr-api.git +``` + +You should post issues or comments on GitHub also: +http://github.com/alexis-mignon/python-flickr-api/ + +The svn repository at least for a while will be kept up-to-date, so that if you want to go on using svn you can do it from: +``` +svn checkout http://python-flickr-api.googlecode.com/svn/trunk/ python-flickr-api +``` + +I have been recently working on a new version of the api using different programming paradigms. It uses meta classes and decorators to implement the api calls and generate the documentation dynamically from Flickr documentation. The result is a much more compact code which stresses the ways the object API is bound to Flickr API. Since a lot of code has been modified it can be unstable and some minor compatibility issues might have appear. + +The current 'stable' (should be frozen) version is available on the downloads page with under the name python-flickr-api\_0.1.zip + + +If you prefer using the previous version of the project please download it from : +``` +svn checkout http://python-flickr-api.googlecode.com/svn/branches/init/ python-flickr-api +``` +or download the archive python-flickr-api\_xxxx.zip on the download page. +If requested this branch can be maintained for little while, since the new version becomes stable. \ No newline at end of file diff --git a/Tutorial.md b/Tutorial.md new file mode 100644 index 0000000..672952f --- /dev/null +++ b/Tutorial.md @@ -0,0 +1,200 @@ +# Introduction # + +This document tries to show some basic usage of flickr\_api. + +# Flickr keys # + +Any application using the Flickr API needs to have a api key and a secret key. Both are provided by Flickr. Please refer to the Flickr instructions to learn how to get thoses keys. + +To be able to use these keys in your application you have two ways: + 1. Set the key information using the 'set\_keys' function. so any application using this API should start with something like: +``` +import flickr_api +flickr_api.set_keys(api_key = 'my_api_key', api_secret = 'my_secret') +``` + 1. provide a flickr\_keys.py setting module with the keys information. It should look like: +``` +API_KEY = 'my_api_key' +API_SECRET = 'my_secret' +``` +This module should be located in your flickr\_api directory or available from your PYTHON\_PATH. + +# Authentication # + +If your application needs to modify data or to access non public material, it will require an authentication token. The AuthHandler object is designed to deal with the authentication process. + +To get an authentication token, the AuthHandler will ask an authorisation request. It will then provide an url at which the user should be redirected so he can grant the required permissions. At the end of the authorisation process a verifier code will be provided. This code must be given to the AuthHandler object which will then be able to get the authentication token. + +Here is an example of how to get this authentication token. + +``` +>>> import flickr_api +>>> a = flickr_api.auth.AuthHandler() #creates the AuthHandler object +>>> perms = "read" # set the required permissions +>>> url = a.get_authorization_url(perms) +>>> print url +``` + +At this time you should copy and paste the printed url in your favorite web browser. Login to Flickr if it is needed and accept the requested permissions. +You will be redirected to an xml page in which there is a "oauth\_verifier" tag. The content of this tag is the verifier that needs to be given to the AuthHandler. + +Note that the url you you are redirected to after you have seccessfully granted the permissions is called the "callback" url. The xml page you have seen corresponds to the default callback url. Within a web application you are supposed to redirect the user to Flickr for the authorisation process. Once it is completed you would like the user to be redirected to a url on your own website which will read automatically the verifier code in the query part of the url. This can be done through the "callback" argument of the AuthHandler constructor. In this case you will want to replace the second line above by something like: + +``` +a = flickr_api.auth.AuthHandler(callback = "http://www.mysite.com/get_verifier/") +``` + +Let's come back to our example. In the xml page, copy the content of the "oauth\_verifier" tag and give it to the AuthHandler object. + +``` +>>> a.set_verifier("the verifier code") +>>> flickr_api.set_auth_handler(a) # set the AuthHandler for the session +``` + +That's it! You are ready to play with your account. The authorisation process is supposed to be done only once so you might want to save the Authentication token: +``` +>>> a.save(filename) +``` +Next time you want to access your account you just need to reload it: +``` +>>> a = flickr_api.auth.AuthHandler.load(filename) +>>> flickr_api.set_auth_handler(a) +``` +Actually there is a shortcut for that: +``` +>>> flickr_api.set_auth_handler(filename) +``` + +# Direct API methods calls # + +You can access the flickr api in two different ways the first one directly calls the api methods with a syntax close to the one that you will find on the api documentation on Flickr's site. + +The answers are xml strings or JSON strings and you will have to parse them yourself. This method is recommended for experimented users only. For other users please refer to the Object Oriented api. + +Here is an example of method call: +``` +>>> from flickr_api.api import flickr +>>> print flickr.reflection.getMethodInfo(method_name = "flickr.photos.getInfo") +``` +``` + + + + Get information about a photo. The calling user must have permission to view the photo. + ... + ... + + + Your API application key. <a href="/services/api/misc.api_keys.html">See here</a> for more details. + ... + + + The photo id was either invalid or was for a photo not viewable by the calling user. + ... + + +``` + +# Object Oriented interface usage # +## Retrieving a user ## + +To have direct access to user you have 3 methods + 1. by username +``` +>>> user = flickr_api.Person.findByUsername(username) +``` + 1. by email +``` +>>> user = flickr_api.Person.findByEmail(email) +``` + 1. If an authentication handlier is set, you can retrieve the authenticated user with : +``` +>>> user = flickr_api.test.login() +``` + +## Managing Photos ## + + * Get photos from a user +``` +>>> photos = user.getPhotos() # if authenticated +>>> photos = user.getPublicPhotos() # otherwise +``` +Some information about the response from the server, e.g. pagination information, are available in the `info` attribute of the `photos` list: +``` +>>> print photos.info.pages # the number of available pages of results +>>> print photos.info.page # the current page number +>>> print photos.info.total # total number of photos +``` + + * Download a photo +``` +>>> p.save(filename, size_label = 'Medium 640') # downloading the photo file +``` + * Upload a photo +``` +>>> flickr_api.upload(photo_file = "path_to_the_photo_file", title = "My title") +``` + * Add/Delete a comment +``` +>>> comment = photo.addComment(comment_text = "A comment") # adding a comment +>>> comment.delete() # deleting the comment +``` + * Retrieve the comments +``` +>>> comments = photo.getComments() +>>> for comment in comments : print comment.text +``` + +## Managing Photosets (aka Albums) ## + * Get the photosets of a user +``` +>>> photosets = user.getPhotosets() +``` + * Create a photoset +``` +>>> photoset = flickr_api.Photoset.create(title = "The title of the photoset", primary_photo = cover_photo) +``` + * Delete a photoset +``` +>>> photoset.delete() +``` + * Get the photos of a photoset +``` +>>> photos = photoset.getPhotos() +``` + * Add a photo to a set +``` +>>> photoset.addPhoto(photo = a_photo) +``` + * Add a comment to a photoset +``` +>>> photoset.addComment(comment_text = "the text of the comment...") +``` + +## Cache ## + +It is possible to cache frequent request to avoid repeated access to Flickr site: +``` +import flickr_api +flickr_api.enable_cache() +``` + +You can also provide customized cache object: +``` +import flickr_api +from flickr_api.cache import SimpleCache +flickr_api.enable_cache(SimpleCache(timeout = 300,max_entries = 10) +``` + +The code for caching comes from the Stuvel's python api. It should then be compliant with Django caching system. + +``` +import flickr_api +from django.core.cache import cache +flickr_api.enable_cache(cache) +``` + +To disable the caching system: +``` +flickr_api.disable_cache() +``` \ No newline at end of file diff --git a/WhytheNewObjectAPI.md b/WhytheNewObjectAPI.md new file mode 100644 index 0000000..c9348cd --- /dev/null +++ b/WhytheNewObjectAPI.md @@ -0,0 +1,59 @@ +# Introduction # +From my point of the the original code of the Object API was extremely redundant and difficult to browse because of its large size. A big part of its size was due to the documentation which I had manually copied from the Flickr API documentation. + +In the new version of the Object API, most of the repetitive code has been removed and replace either by some helper function or more interestingly by an extensive use +of decorators and meta programming. + +This gives a more compact code and I hope easier to maintain. + + +# 'caller' and 'static\_caller' decorators # +Since an object methods is an abstraction of the call to a Flickr API method, I wanted the code to reflect this relation. Now an Object method bound to a Flickr API method is explicitly indicated as such through the use of the 'caller' decorator. + +For instance this is the code of the 'Photo.search' method: +``` + @static_caller("flickr.photos.search") + def search(**args): + args = _format_id("user",args) + args = _format_extras(args) + return args,_extract_photo_list +``` + +Since this is a static method we use the 'static\_caller' decorator which take as argument the Flickr API method it uses internally. The body of the function does two things: + 1. It pre-format the arguments that we be use for the api call + 1. It returns a function that will process the result from Flickr API and reformat it into Objects. + +Written this way the code makes explicit the way the binding is done: + 1. Which api method is called ? + 1. Do the arguments need to be pre-formated ? + 1. How to interpret the respsonse from Flickr servers ? + +Note that `static_caller` inherits from `staticmethod` so you must not add the +static method decorator. + +# Where is the documentation ? # + +This is a controversial point. The code is generated dynamically from the method descriptions given by Flickr through the `flickr.reflection.getMethodInfo` api method. + +Since make calls to flickr servers for all methods can take time it has been done once for all and the result is saved as a dictionnary into the 'methods' module which is automatically generated using the `write_reflection` function from the `tools` module. You have two ways to have access to the documentation of a method: + 1. in the interactive console (by using either help(method) or print method.doc) + 1. or using pydoc which generates the documentation automatically, so you have a nice browsable html documentation. + +# How does reflection work ? # + +First the documentation for all flickr method has be downloaded using `flickr.reflection.getMethods` to get the list of Flickr API methods, and then +`flickr.reflection.methodInfo` to get the documentation of each method. The result is stored as a dictionnary in the `flickr_api.methods` module. + +The reflection mechanism for the object api (available from `flickr_api.objects`) is then implemented in the `flickr_api.reflection` module and consists in two main components: + 1. The `caller` and `static_caller` decorators. + 1. The `FlickrAutoDoc` meta class. + +Both components act together to add the reflection capabilities. The `caller` and `static_caller` decorators add a `flickr_method` as well as a `isstatic` attribtues to each method. This allows the user to know which Flickr method is used +to access Flickr's servers. It is also used by the meta class `FlickrAutoDoc` to dynamically add the documentation of the method. +`FlickrAutoDoc` also keep tracks of the bindings between Flickr methods and object methods so you can know which object methods are bound to a given Flickr method using the `bindings_to` function: + +``` +>>> from flickr_api import reflection +>>> reflection.bindings_to("flickr.people.getPhotos") +['Person.getPhotos'] +``` \ No newline at end of file