instead to achieve the same effect.
"""
if self.in_canvas:
return HttpResponse('' % (url, ))
elif re.search("^https?:\/\/([^\/]*\.)?facebook\.com(:\d+)?", url.lower()):
return HttpResponse('' % url)
else:
return HttpResponseRedirect(url)
def get_facebook_client():
"""
Get the current Facebook object for the calling thread.
"""
try:
return _thread_locals.facebook
except AttributeError:
raise ImproperlyConfigured('Make sure you have the Facebook middleware installed.')
def require_login(next=None, internal=None):
"""
Decorator for Django views that requires the user to be logged in.
The FacebookMiddleware must be installed.
Standard usage:
@require_login()
def some_view(request):
...
Redirecting after login:
To use the 'next' parameter to redirect to a specific page after login, a callable should
return a path relative to the Post-add URL. 'next' can also be an integer specifying how many
parts of request.path to strip to find the relative URL of the canvas page. If 'next' is None,
settings.callback_path and settings.app_name are checked to redirect to the same page after logging
in. (This is the default behavior.)
@require_login(next=some_callable)
def some_view(request):
...
"""
def decorator(view):
def newview(request, *args, **kwargs):
next = newview.next
internal = newview.internal
try:
fb = request.facebook
except:
raise ImproperlyConfigured('Make sure you have the Facebook middleware installed.')
if internal is None:
internal = request.facebook.internal
if callable(next):
next = next(request.path)
elif isinstance(next, int):
next = '/'.join(request.path.split('/')[next + 1:])
elif next is None and fb.callback_path and request.path.startswith(fb.callback_path):
next = request.path[len(fb.callback_path):]
elif not isinstance(next, str):
next = ''
if not fb.check_session(request):
#If user has never logged in before, the get_login_url will redirect to the TOS page
return fb.redirect(fb.get_login_url(next=next))
if internal and request.method == 'GET' and fb.app_name:
return fb.redirect('%s%s' % (fb.get_app_url(), next))
return view(request, *args, **kwargs)
newview.next = next
newview.internal = internal
return newview
return decorator
def require_add(next=None, internal=None, on_install=None):
"""
Decorator for Django views that requires application installation.
The FacebookMiddleware must be installed.
Standard usage:
@require_add()
def some_view(request):
...
Redirecting after installation:
To use the 'next' parameter to redirect to a specific page after login, a callable should
return a path relative to the Post-add URL. 'next' can also be an integer specifying how many
parts of request.path to strip to find the relative URL of the canvas page. If 'next' is None,
settings.callback_path and settings.app_name are checked to redirect to the same page after logging
in. (This is the default behavior.)
@require_add(next=some_callable)
def some_view(request):
...
Post-install processing:
Set the on_install parameter to a callable in order to handle special post-install processing.
The callable should take a request object as the parameter.
@require_add(on_install=some_callable)
def some_view(request):
...
"""
def decorator(view):
def newview(request, *args, **kwargs):
next = newview.next
internal = newview.internal
try:
fb = request.facebook
except:
raise ImproperlyConfigured('Make sure you have the Facebook middleware installed.')
if internal is None:
internal = request.facebook.internal
if callable(next):
next = next(request.path)
elif isinstance(next, int):
next = '/'.join(request.path.split('/')[next + 1:])
elif next is None and fb.callback_path and request.path.startswith(fb.callback_path):
next = request.path[len(fb.callback_path):]
else:
next = ''
if not fb.check_session(request):
if fb.added:
if request.method == 'GET' and fb.app_name:
return fb.redirect('%s%s' % (fb.get_app_url(), next))
return fb.redirect(fb.get_login_url(next=next))
else:
return fb.redirect(fb.get_add_url(next=next))
if not fb.added:
return fb.redirect(fb.get_add_url(next=next))
if 'installed' in request.GET and callable(on_install):
on_install(request)
if internal and request.method == 'GET' and fb.app_name:
return fb.redirect('%s%s' % (fb.get_app_url(), next))
return view(request, *args, **kwargs)
newview.next = next
newview.internal = internal
return newview
return decorator
# try to preserve the argspecs
try:
import decorator
except ImportError:
pass
else:
def updater(f):
def updated(*args, **kwargs):
original = f(*args, **kwargs)
def newdecorator(view):
return decorator.new_wrapper(original(view), view)
return decorator.new_wrapper(newdecorator, original)
return decorator.new_wrapper(updated, f)
require_login = updater(require_login)
require_add = updater(require_add)
class FacebookMiddleware(object):
"""
Middleware that attaches a Facebook object to every incoming request.
The Facebook object created can also be accessed from models for the
current thread by using get_facebook_client().
"""
def __init__(self, api_key=None, secret_key=None, app_name=None, callback_path=None, internal=None):
self.api_key = api_key or settings.FACEBOOK_API_KEY
self.secret_key = secret_key or settings.FACEBOOK_SECRET_KEY
self.app_name = app_name or getattr(settings, 'FACEBOOK_APP_NAME', None)
self.callback_path = callback_path or getattr(settings, 'FACEBOOK_CALLBACK_PATH', None)
self.internal = internal or getattr(settings, 'FACEBOOK_INTERNAL', True)
self.proxy = None
if getattr(settings, 'USE_HTTP_PROXY', False):
self.proxy = settings.HTTP_PROXY
def process_request(self, request):
_thread_locals.facebook = request.facebook = Facebook(self.api_key, self.secret_key, app_name=self.app_name, callback_path=self.callback_path, internal=self.internal, proxy=self.proxy)
if not self.internal:
if 'fb_sig_session_key' in request.GET and 'fb_sig_user' in request.GET:
request.facebook.session_key = request.session['facebook_session_key'] = request.GET['fb_sig_session_key']
request.facebook.uid = request.session['fb_sig_user'] = request.GET['fb_sig_user']
elif request.session.get('facebook_session_key', None) and request.session.get('facebook_user_id', None):
request.facebook.session_key = request.session['facebook_session_key']
request.facebook.uid = request.session['facebook_user_id']
def process_response(self, request, response):
if not self.internal and request.facebook.session_key and request.facebook.uid:
request.session['facebook_session_key'] = request.facebook.session_key
request.session['facebook_user_id'] = request.facebook.uid
if request.facebook.session_key_expires:
expiry = datetime.datetime.fromtimestamp(request.facebook.session_key_expires)
request.session.set_expiry(expiry)
try:
fb = request.facebook
except:
return response
if not fb.is_session_from_cookie:
# Make sure the browser accepts our session cookies inside an Iframe
response['P3P'] = 'CP="NOI DSP COR NID ADMa OPTa OUR NOR"'
fb_cookies = {
'expires': fb.session_key_expires,
'session_key': fb.session_key,
'user': fb.uid,
}
expire_time = None
if fb.session_key_expires:
expire_time = datetime.utcfromtimestamp(fb.session_key_expires)
for k in fb_cookies:
response.set_cookie(self.api_key + '_' + k, fb_cookies[k], expires=expire_time)
response.set_cookie(self.api_key , fb._hash_args(fb_cookies), expires=expire_time)
return response
python-facebook-0.svn20100209/facebook/djangofb/models.py 0000644 0001750 0001750 00000001743 11315701561 021571 0 ustar ianw ianw from django.db import models
from django.utils.html import escape
from django.utils.safestring import mark_safe
FB_MESSAGE_STATUS = (
(0, 'Explanation'),
(1, 'Error'),
(2, 'Success'),
)
class MessageManager(models.Manager):
def get_and_delete_all(self, uid):
messages = []
for m in self.filter(uid=uid):
messages.append(m)
m.delete()
return messages
class Message(models.Model):
"""Represents a message for a Facebook user."""
uid = models.CharField(max_length=25)
status = models.IntegerField(choices=FB_MESSAGE_STATUS)
message = models.CharField(max_length=300)
objects = MessageManager()
def __unicode__(self):
return self.message
def _fb_tag(self):
return self.get_status_display().lower()
def as_fbml(self):
return mark_safe(u'' % (
self._fb_tag(),
escape(self.message),
))
python-facebook-0.svn20100209/facebook/djangofb/default_app/ 0000755 0001750 0001750 00000000000 11315701561 022213 5 ustar ianw ianw python-facebook-0.svn20100209/facebook/djangofb/default_app/views.py 0000644 0001750 0001750 00000002536 11315701561 023730 0 ustar ianw ianw from django.http import HttpResponse
from django.views.generic.simple import direct_to_template
#uncomment the following two lines and the one below
#if you dont want to use a decorator instead of the middleware
#from django.utils.decorators import decorator_from_middleware
#from facebook.djangofb import FacebookMiddleware
# Import the Django helpers
import facebook.djangofb as facebook
# The User model defined in models.py
from models import User
# We'll require login for our canvas page. This
# isn't necessarily a good idea, as we might want
# to let users see the page without granting our app
# access to their info. See the wiki for details on how
# to do this.
#@decorator_from_middleware(FacebookMiddleware)
@facebook.require_login()
def canvas(request):
# Get the User object for the currently logged in user
user = User.objects.get_current()
# Check if we were POSTed the user's new language of choice
if 'language' in request.POST:
user.language = request.POST['language'][:64]
user.save()
# User is guaranteed to be logged in, so pass canvas.fbml
# an extra 'fbuser' parameter that is the User object for
# the currently logged in user.
return direct_to_template(request, 'canvas.fbml', extra_context={'fbuser': user})
@facebook.require_login()
def ajax(request):
return HttpResponse('hello world')
python-facebook-0.svn20100209/facebook/djangofb/default_app/__init__.py 0000644 0001750 0001750 00000000000 11315701561 024312 0 ustar ianw ianw python-facebook-0.svn20100209/facebook/djangofb/default_app/models.py 0000644 0001750 0001750 00000002142 11315701561 024047 0 ustar ianw ianw from django.db import models
# get_facebook_client lets us get the current Facebook object
# from outside of a view, which lets us have cleaner code
from facebook.djangofb import get_facebook_client
class UserManager(models.Manager):
"""Custom manager for a Facebook User."""
def get_current(self):
"""Gets a User object for the logged-in Facebook user."""
facebook = get_facebook_client()
user, created = self.get_or_create(id=int(facebook.uid))
if created:
# we could do some custom actions for new users here...
pass
return user
class User(models.Model):
"""A simple User model for Facebook users."""
# We use the user's UID as the primary key in our database.
id = models.IntegerField(primary_key=True)
# TODO: The data that you want to store for each user would go here.
# For this sample, we let users let people know their favorite progamming
# language, in the spirit of Extended Info.
language = models.CharField(maxlength=64, default='Python')
# Add the custom manager
objects = UserManager()
python-facebook-0.svn20100209/facebook/djangofb/default_app/templates/ 0000755 0001750 0001750 00000000000 11315701561 024211 5 ustar ianw ianw python-facebook-0.svn20100209/facebook/djangofb/default_app/templates/canvas.fbml 0000644 0001750 0001750 00000001452 11315701561 026330 0 ustar ianw ianw
{% comment %}
We can use {{ fbuser }} to get at the current user.
{{ fbuser.id }} will be the user's UID, and {{ fbuser.language }}
is his/her favorite language (Python :-).
{% endcomment %}
Welcome, !
Your favorite language is {{ fbuser.language|escape }}.
python-facebook-0.svn20100209/facebook/djangofb/default_app/urls.py 0000644 0001750 0001750 00000000254 11315701561 023553 0 ustar ianw ianw from django.conf.urls.defaults import *
urlpatterns = patterns('{{ project }}.{{ app }}.views',
(r'^$', 'canvas'),
# Define other pages you want to create here
)
python-facebook-0.svn20100209/examples/ 0000755 0001750 0001750 00000000000 11315701561 016222 5 ustar ianw ianw python-facebook-0.svn20100209/examples/pyfacebook_sample/ 0000755 0001750 0001750 00000000000 11315701561 021705 5 ustar ianw ianw python-facebook-0.svn20100209/examples/pyfacebook_sample/views.py 0000644 0001750 0001750 00000003113 11315701561 023412 0 ustar ianw ianw from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import render_to_response
#uncomment the following two lines and the one below
#if you dont want to use a decorator instead of the middleware
#from django.utils.decorators import decorator_from_middleware
#from facebook.djangofb import FacebookMiddleware
import facebook.djangofb as facebook
#@decorator_from_middleware(FacebookMiddleware)
@facebook.require_login()
def canvas(request):
# If you're using FBML, it'd be better to use than to do this - this is just as an example
values = request.facebook.users.getInfo([request.facebook.uid], ['first_name', 'is_app_user', 'has_added_app'])[0]
name, is_app_user, has_added_app = values['first_name'], values['is_app_user'], values['has_added_app']
if has_added_app == '0':
return request.facebook.redirect(request.facebook.get_add_url())
return render_to_response('facebook/canvas.fbml', {'name': name})
@facebook.require_login()
def post(request):
request.facebook.profile.setFBML(request.POST['profile_text'], request.facebook.uid)
return request.facebook.redirect(request.facebook.get_url('profile', id=request.facebook.uid))
@facebook.require_login()
def post_add(request):
request.facebook.profile.setFBML(uid=request.facebook.uid, profile='Congratulations on adding PyFaceBook. Please click on the PyFaceBook link on the left side to change this text.')
return request.facebook.redirect('http://apps.facebook.com/pyfacebook/')
@facebook.require_login()
def ajax(request):
return HttpResponse('hello world')
python-facebook-0.svn20100209/examples/pyfacebook_sample/__init__.py 0000644 0001750 0001750 00000000000 11315701561 024004 0 ustar ianw ianw python-facebook-0.svn20100209/examples/pyfacebook_sample/models.py 0000644 0001750 0001750 00000000000 11315701561 023530 0 ustar ianw ianw python-facebook-0.svn20100209/examples/pyfacebook_sample/templates/ 0000755 0001750 0001750 00000000000 11315701561 023703 5 ustar ianw ianw python-facebook-0.svn20100209/examples/pyfacebook_sample/templates/facebook/ 0000755 0001750 0001750 00000000000 11315701561 025454 5 ustar ianw ianw python-facebook-0.svn20100209/examples/pyfacebook_sample/templates/facebook/canvas.fbml 0000644 0001750 0001750 00000001120 11315701561 027563 0 ustar ianw ianw
Welcome, {{ name }}!
This is the sample PyFaceBook application.
python-facebook-0.svn20100209/examples/pyfacebook_sample/README 0000644 0001750 0001750 00000002751 11315701561 022572 0 ustar ianw ianw This is a sample Django application for PyFacebook.
To use this application, copy the entire folder to an existing
Django application. Then you need to edit the following settings:
* In settings.py, make sure that TEMPLATE_LOADERS contains
'django.template.loaders.app_directories.load_template_source'. This
is so that templates can be loaded from this template directory.
* In settings.py, define FACEBOOK_API_KEY and FACEBOOK_SECRET_KEY to your
own values.
* In settings.py, add the following line to the variable MIDDLEWARE_CLASSES:
'facebook.djangofb.FacebookMiddleware'. This will attach a facebook object
to every incoming request.
* However if you don't wan't to attach a facebook object to every incoming
request you can use the middleware as a decorator.
from django.utils.decorators import decorator_from_middleware
from facebook.djangofb import FacebookMiddleware
@decorator_from_middleware(FacebookMiddleware)
@facebook.require_login()
def canvas(request):
...
* In urls.py, have something in your urlpatterns like:
(r'^facebook/', include('YOUR_PROJECT_NAME.pyfacebook_sample.urls')),
This will tell the sample application to live under /facebook/.
* On the Facebook applications page, make sure that you set your callback
to the appropriate URL. In this example, it would be
'http://YOUR_IP/facebook/canvas/', and DON'T FORGET THE TRAILING SLASH :-)
* Change any occurrences of pyfacebook to your own application name.
That should be about it...
python-facebook-0.svn20100209/examples/pyfacebook_sample/urls.py 0000644 0001750 0001750 00000001330 11315701561 023241 0 ustar ianw ianw from django.conf.urls.defaults import *
# Hack to get the project name
project = __name__.split('.')[0]
# You'd want to change this to wherever your app lives
urlpatterns = patterns(project + '.pyfacebook_sample.views',
# Some functionality - users can post text to their homepage
(r'^canvas/post/', 'post'),
# For the mock AJAX functionality
(r'^canvas/ajax/', 'ajax'),
# This is the canvas callback, i.e. what will be seen
# when you visit http://apps.facebook.com/.
(r'^canvas/', 'canvas'),
# Extra callbacks can be set in the Facebook app settings
# page. For example, post_add will be called when a user
# has added the application.
(r'^post_add/', 'post_add'),
)
python-facebook-0.svn20100209/examples/examples.py 0000644 0001750 0001750 00000007057 11315701561 020423 0 ustar ianw ianw # -----------------------
# Web application example
# -----------------------
def simple_web_app(request, api_key, secret_key):
fb = Facebook(api_key, secret_key, request.GET['auth_token'])
fb.auth.getSession()
friend_ids = fb.friends.get()
info = fb.users.getInfo(friend_ids, ['name', 'pic'])
print ''
for friend in info:
print '%(name)s' % friend
print ''
def web_app(request):
"""Get the user's friends and their pictures. This example uses
the Django web framework, but should be adaptable to others."""
# Get api_key and secret_key from a file
fb_file = open('facebook_keys.txt').readlines()
api_key = fb_file[0].strip()
secret_key = fb_file[1].strip()
fb = Facebook(api_key, secret_key)
# Use the data from the cookie if present
if 'session_key' in request.session and 'uid' in request.session:
fb.session_key = request.session['session_key']
fb.uid = request.session['uid']
else:
try:
fb.auth_token = request.GET['auth_token']
except KeyError:
# Send user to the Facebook to login
return HttpResponseRedirect(fb.get_login_url())
# getSession sets the session_key and uid
# Store these in the cookie so we don't have to get them again
fb.auth.getSession()
request.session['session_key'] = fb.session_key
request.session['uid'] = fb.uid
try:
friend_ids = fb.friends.get()
except FacebookError, e:
# Error 102 means the session has expired.
# Delete the cookie and send the user to Facebook to login
if e.info['code'] == u'102':
del request.session['session_key']
del request.session['uid']
return HttpResponseRedirect(fb.get_login_url())
else:
# Other Facebook errors are possible too. Don't ignore them.
raise
info = fb.users.getInfo(friend_ids, ['name', 'pic'])
# info is a list of dictionaries
# you would never do this in an actual Django application,
# it's just an example of accessing the results.
links = []
for friend in info:
html = '%(name)s' % friend
links.append(html)
return render_to_response('template.html', {'links': links})
# ---------------------------
# Desktop application example
# ---------------------------
def desktop_app():
from facebook import Facebook
# Get api_key and secret_key from a file
fbs = open(FB_SETTINGS).readlines()
facebook = Facebook(fbs[0].strip(), fbs[1].strip())
facebook.auth.createToken()
# Show login window
facebook.login()
# Login to the window, then press enter
print 'After logging in, press enter...'
raw_input()
facebook.auth.getSession()
info = facebook.users.getInfo([facebook.uid], ['name', 'birthday', 'affiliations', 'sex'])[0]
for attr in info:
print '%s: %s' % (attr, info[attr])
friends = facebook.friends.get()
friends = facebook.users.getInfo(friends[0:5], ['name', 'birthday', 'relationship_status'])
for friend in friends:
if 'birthday' in friend:
print friend['name'], 'has a birthday on', friend['birthday'], 'and is', friend['relationship_status']
else:
print friend['name'], 'has no birthday and is', friend['relationship_status']
arefriends = facebook.friends.areFriends([friends[0]['uid']], [friends[1]['uid']])
photos = facebook.photos.getAlbums(friends[1]['uid'])
print photos
python-facebook-0.svn20100209/.gitignore 0000644 0001750 0001750 00000000006 11315701561 016370 0 ustar ianw ianw *.py?
python-facebook-0.svn20100209/README 0000644 0001750 0001750 00000004777 11315701561 015303 0 ustar ianw ianw == PyFacebook ==
PyFacebook is a Python client library for the Facebook API.
Samuel Cormier-Iijima (sciyoshi@gmail.com)
Niran Babalola (iamniran@gmail.com)
Shannon -jj Behrens (jjinux@gmail.com)
David B. Edelstein (David.B.Edelstein@gmail.com)
Max Battcher (max.battcher@gmail.com)
Rohan Deshpande (rohan.deshpande@gmail.com)
Matthew Stevens (matthew.stevens@gmail.com)
Sandro Turriate (sandro.turriate@gmail.com)
Benjamin Zimmerman (benjamin.zimmerman@gmail.com)
Gisle Aas (gisle.aas@gmail.com)
Rand Bradley (rand.bradley@gmail.com)
Luke Worth (luke.worth@gmail.com)
Andreas Cederström (andreas@klydd.se)
Samuel Hoffstaetter (samuel@hoffstaetter.com)
http://github.com/sciyoshi/pyfacebook/
== Usage ==
To use this in your own projects, do the standard:
python setup.py install
== Documentation ==
Have a look at the examples/ directory. Most of the stuff should be
self-explanatory. There is also an example Django app in
examples/facebook, which should have enough to get you started.
See the developer wiki for more information.
== License ==
Copyright (c) 2008, Samuel Cormier-Iijima
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its contributors may
be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS``AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
python-facebook-0.svn20100209/tests/ 0000755 0001750 0001750 00000000000 11315701561 015546 5 ustar ianw ianw python-facebook-0.svn20100209/tests/minimock.py 0000644 0001750 0001750 00000021676 11315701561 017742 0 ustar ianw ianw # (c) 2006 Ian Bicking, Mike Beachy, and contributors
# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
r"""
minimock is a simple library for doing Mock objects with doctest.
When using doctest, mock objects can be very simple.
Here's an example of something we might test, a simple email sender::
>>> import smtplib
>>> def send_email(from_addr, to_addr, subject, body):
... conn = smtplib.SMTP('localhost')
... msg = 'To: %s\nFrom: %s\nSubject: %s\n\n%s' % (
... to_addr, from_addr, subject, body)
... conn.sendmail(from_addr, [to_addr], msg)
... conn.quit()
Now we want to make a mock ``smtplib.SMTP`` object. We'll have to
inject our mock into the ``smtplib`` module::
>>> smtplib.SMTP = Mock('smtplib.SMTP')
>>> smtplib.SMTP.mock_returns = Mock('smtp_connection')
Now we do the test::
>>> send_email('ianb@colorstudy.com', 'joe@example.com',
... 'Hi there!', 'How is it going?')
Called smtplib.SMTP('localhost')
Called smtp_connection.sendmail(
'ianb@colorstudy.com',
['joe@example.com'],
'To: joe@example.com\nFrom: ianb@colorstudy.com\nSubject: Hi there!\n\nHow is it going?')
Called smtp_connection.quit()
Voila! We've tested implicitly that no unexpected methods were called
on the object. We've also tested the arguments that the mock object
got. We've provided fake return calls (for the ``smtplib.SMTP()``
constructor). These are all the core parts of a mock library. The
implementation is simple because most of the work is done by doctest.
"""
import warnings
warnings.warn(
"The module from http://svn.colorstudy.com/home/ianb/recipes/minimock.py is deprecated; "
"please install the MiniMock package",
DeprecationWarning, stacklevel=2)
__all__ = ["mock", "restore", "Mock"]
import inspect
# A list of mocked objects. Each item is a tuple of (original object,
# namespace dict, object name, and a list of object attributes).
#
mocked = []
def lookup_by_name(name, nsdicts):
"""
Look up an object by name from a sequence of namespace dictionaries.
Returns a tuple of (nsdict, object, attributes); nsdict is the
dictionary the name was found in, object is the base object the name is
bound to, and the attributes list is the chain of attributes of the
object that complete the name.
>>> import os
>>> nsdict, name, attributes = lookup_by_name("os.path.isdir",
... (locals(),))
>>> name, attributes
('os', ['path', 'isdir'])
>>> nsdict, name, attributes = lookup_by_name("os.monkey", (locals(),))
Traceback (most recent call last):
...
NameError: name 'os.monkey' is not defined
"""
for nsdict in nsdicts:
attrs = name.split(".")
names = []
while attrs:
names.append(attrs.pop(0))
obj_name = ".".join(names)
if obj_name in nsdict:
attr_copy = attrs[:]
tmp = nsdict[obj_name]
try:
while attr_copy:
tmp = getattr(tmp, attr_copy.pop(0))
except AttributeError:
pass
else:
return nsdict, obj_name, attrs
raise NameError("name '%s' is not defined" % name)
def mock(name, nsdicts=None, mock_obj=None, **kw):
"""
Mock the named object, placing a Mock instance in the correct namespace
dictionary. If no iterable of namespace dicts is provided, use
introspection to get the locals and globals of the caller of this
function.
All additional keyword args are passed on to the Mock object
initializer.
An example of how os.path.isfile is replaced:
>>> import os
>>> os.path.isfile
>>> isfile_id = id(os.path.isfile)
>>> mock("os.path.isfile", returns=True)
>>> os.path.isfile
>>> os.path.isfile("/foo/bar/baz")
Called os.path.isfile('/foo/bar/baz')
True
>>> mock_id = id(os.path.isfile)
>>> mock_id != isfile_id
True
A second mock object will replace the first, but the original object
will be the one replaced with the replace() function.
>>> mock("os.path.isfile", returns=False)
>>> mock_id != id(os.path.isfile)
True
>>> restore()
>>> os.path.isfile
>>> isfile_id == id(os.path.isfile)
True
"""
if nsdicts is None:
stack = inspect.stack()
try:
# stack[1][0] is the frame object of the caller to this function
globals_ = stack[1][0].f_globals
locals_ = stack[1][0].f_locals
nsdicts = (locals_, globals_)
finally:
del(stack)
if mock_obj is None:
mock_obj = Mock(name, **kw)
nsdict, obj_name, attrs = lookup_by_name(name, nsdicts)
# Get the original object and replace it with the mock object.
tmp = nsdict[obj_name]
if not attrs:
original = tmp
nsdict[obj_name] = mock_obj
else:
for attr in attrs[:-1]:
tmp = getattr(tmp, attr)
original = getattr(tmp, attrs[-1])
setattr(tmp, attrs[-1], mock_obj)
mocked.append((original, nsdict, obj_name, attrs))
def restore():
"""
Restore all mocked objects.
"""
global mocked
# Restore the objects in the reverse order of their mocking to assure
# the original state is retrieved.
while mocked:
original, nsdict, name, attrs = mocked.pop()
if not attrs:
nsdict[name] = original
else:
tmp = nsdict[name]
for attr in attrs[:-1]:
tmp = getattr(tmp, attr)
setattr(tmp, attrs[-1], original)
return
class Mock(object):
def __init__(self, name, returns=None, returns_iter=None,
returns_func=None, raises=None):
self.mock_name = name
self.mock_returns = returns
if returns_iter is not None:
returns_iter = iter(returns_iter)
self.mock_returns_iter = returns_iter
self.mock_returns_func = returns_func
self.mock_raises = raises
self.mock_attrs = {}
def __repr__(self):
return '' % (hex(id(self)), self.mock_name)
def __call__(self, *args, **kw):
parts = [repr(a) for a in args]
parts.extend(
'%s=%r' % (items) for items in sorted(kw.items()))
msg = 'Called %s(%s)' % (self.mock_name, ', '.join(parts))
if len(msg) > 80:
msg = 'Called %s(\n %s)' % (
self.mock_name, ',\n '.join(parts))
print msg
return self._mock_return(*args, **kw)
def _mock_return(self, *args, **kw):
if self.mock_raises is not None:
raise self.mock_raises
elif self.mock_returns is not None:
return self.mock_returns
elif self.mock_returns_iter is not None:
try:
return self.mock_returns_iter.next()
except StopIteration:
raise Exception("No more mock return values are present.")
elif self.mock_returns_func is not None:
return self.mock_returns_func(*args, **kw)
else:
return None
def __getattr__(self, attr):
if attr not in self.mock_attrs:
if self.mock_name:
new_name = self.mock_name + '.' + attr
else:
new_name = attr
self.mock_attrs[attr] = Mock(new_name)
return self.mock_attrs[attr]
__test__ = {
"mock" :
r"""
An additional test for mocking a function accessed directly (i.e.
not via object attributes).
>>> import os
>>> rename = os.rename
>>> orig_id = id(rename)
>>> mock("rename")
>>> mock_id = id(rename)
>>> mock("rename")
>>> mock_id != id(rename)
True
>>> restore()
>>> orig_id == id(rename) == id(os.rename)
True
The example from the module docstring, done with the mock/restore
functions.
>>> import smtplib
>>> def send_email(from_addr, to_addr, subject, body):
... conn = smtplib.SMTP('localhost')
... msg = 'To: %s\nFrom: %s\nSubject: %s\n\n%s' % (
... to_addr, from_addr, subject, body)
... conn.sendmail(from_addr, [to_addr], msg)
... conn.quit()
>>> mock("smtplib.SMTP", returns=Mock('smtp_connection'))
>>> send_email('ianb@colorstudy.com', 'joe@example.com',
... 'Hi there!', 'How is it going?')
Called smtplib.SMTP('localhost')
Called smtp_connection.sendmail(
'ianb@colorstudy.com',
['joe@example.com'],
'To: joe@example.com\nFrom: ianb@colorstudy.com\nSubject: Hi there!\n\nHow is it going?')
Called smtp_connection.quit()
>>> restore()
""",
}
if __name__ == '__main__':
import doctest
doctest.testmod(optionflags=doctest.ELLIPSIS)
python-facebook-0.svn20100209/tests/test.py 0000644 0001750 0001750 00000026642 11315701561 017111 0 ustar ianw ianw import unittest
import sys
import os
import facebook
import urllib2
import md5
try:
import simplejson
except ImportError:
from django.utils import simplejson
import httplib
from minimock import Mock
my_api_key = "e1e9cfeb5e0d7a52e4fbd5d09e1b873e"
my_secret_key = "1bebae7283f5b79aaf9b851addd55b90"
#'{"error_code":100,\
#"error_msg":"Invalid parameter",\
#"request_args":[{"key":"format","value":"JSON"},\
#{"key":"auth_token","value":"24626e24bb12919f2f142145070542e8"},\
#{"key":"sig","value":"36af2af3b93da784149301e77cb1621a"},\
#{"key":"v","value":"1.0"},\
#{"key":"api_key","value":"e1e9cfeb5e0d7a52e4fbd5d09e1b873e"},\
#{"key":"method","value":"facebook.auth.getSession"}]}'
response_str = '{"stuff":"abcd"}'
class MyUrlOpen:
def __init__(self,*args,**kwargs):
pass
def read(self):
global response_str
return response_str
class pyfacebook_UnitTests(unittest.TestCase):
def setUp(self):
facebook.urllib2.urlopen = Mock('urllib2.urlopen')
facebook.urllib2.urlopen.mock_returns_func = MyUrlOpen
pass
def tearDown(self):
pass
def login(self):
pass
def test1(self):
f = facebook.Facebook(api_key=my_api_key, secret_key=my_secret_key)
f.login = self.login
self.assertEquals(f.api_key,my_api_key)
self.assertEquals(f.secret_key,my_secret_key)
self.assertEquals(f.auth_token,None)
self.assertEquals(f.app_name,None)
self.assertEquals(f.callback_path,None)
self.assertEquals(f.internal,None)
def test2(self):
args = {"arg1":"a","arg2":"b","arg3":"c"}
hasher = md5.new(''.join(['%s=%s' % (x, args[x]) for x in sorted(args.keys())]))
hasher.update("acdnj")
f = facebook.Facebook(api_key="abcdf", secret_key="acdnj")
f.login = self.login
digest = f._hash_args(args)
self.assertEquals(hasher.hexdigest(),digest)
hasher = md5.new(''.join(['%s=%s' % (x, args[x]) for x in sorted(args.keys())]))
hasher.update("klmn")
# trunk code has error hash.updated instead of hash.update
digest = f._hash_args(args,secret="klmn")
self.assertEquals(hasher.hexdigest(),digest)
hasher = md5.new(''.join(['%s=%s' % (x, args[x]) for x in sorted(args.keys())]))
f.secret = "klmn"
hasher.update(f.secret)
# trunk code has error hash.updated instead of hash.update
digest = f._hash_args(args)
self.assertEquals(hasher.hexdigest(),digest)
def test3(self):
global response_str
response = {'stuff':'abcd'}
response_str = simplejson.dumps(response)
fb = facebook.Facebook(my_api_key, my_secret_key)
fb.login = self.login
fb.auth.createToken()
self.assertEquals(str(fb.auth_token['stuff']),"abcd")
fb.login()
response = {"session_key":"key","uid":"my_uid","secret":"my_secret","expires":"my_expires"}
response_str = simplejson.dumps(response)
res = fb.auth.getSession()
self.assertEquals(str(res["expires"]),response["expires"])
self.assertEquals(str(res["secret"]),response["secret"])
self.assertEquals(str(res["session_key"]),response["session_key"])
self.assertEquals(str(res["uid"]),response["uid"])
def test4(self):
global response_str
response = 'abcdef'
response_str = simplejson.dumps(response)
fb = facebook.Facebook(my_api_key, my_secret_key)
fb.login = self.login
fb.auth.createToken()
self.assertEquals(str(fb.auth_token),"abcdef")
url = fb.get_login_url(next="nowhere", popup=True, canvas=True)
self.assertEquals(url,
'http://www.facebook.com/login.php?canvas=1&popup=1&auth_token=abcdef&next=nowhere&v=1.0&api_key=%s'%(my_api_key,))
def test5(self):
class Request:
def __init__(self,post,get,method):
self.POST = post
self.GET = get
self.method = method
req = Request({'fb_sig_in_canvas':1},{},'POST')
fb = facebook.Facebook(my_api_key, my_secret_key)
fb.login = self.login
res = fb.check_session(req)
self.assertFalse(res)
req = Request({'fb_sig':1},{},'POST')
res = fb.check_session(req)
self.assertFalse(res)
req = Request({'fb_sig':fb._hash_args({'in_canvas':'1',
'added':'1',
'expires':'1',
'friends':'joe,mary',
'session_key':'abc',
'user':'bob'}),
'fb_sig_in_canvas':'1',
'fb_sig_added':'1',
'fb_sig_expires':'1',
'fb_sig_friends':'joe,mary',
'fb_sig_session_key':'abc',
'fb_sig_user':'bob'},
{},'POST')
res = fb.check_session(req)
self.assertTrue(res)
fb = facebook.Facebook(my_api_key, my_secret_key)
fb.login = self.login
req = Request({'fb_sig':fb._hash_args({'in_canvas':'1',
'added':'1',
'expires':'1',
'friends':'',
'session_key':'abc',
'user':'bob'}),
'fb_sig_in_canvas':'1',
'fb_sig_added':'1',
'fb_sig_expires':'1',
'fb_sig_friends':'',
'fb_sig_session_key':'abc',
'fb_sig_user':'bob'},
{},'POST')
res = fb.check_session(req)
self.assertTrue(res)
fb = facebook.Facebook(my_api_key, my_secret_key)
fb.login = self.login
req = Request({'fb_sig':fb._hash_args({'in_canvas':'1',
'added':'1',
'expires':'1',
'friends':'',
'session_key':'abc',
'page_id':'id'}),
'fb_sig_in_canvas':'1',
'fb_sig_added':'1',
'fb_sig_expires':'1',
'fb_sig_friends':'',
'fb_sig_session_key':'abc',
'fb_sig_page_id':'id'},
{},'POST')
res = fb.check_session(req)
self.assertTrue(res)
def test6(self):
global response_str
response = 'abcdef'
response_str = simplejson.dumps(response)
fb = facebook.Facebook(my_api_key, my_secret_key)
fb.login = self.login
fb.auth.createToken()
# self.failUnlessRaises(RuntimeError,fb._add_session_args)
response = {"session_key":"key","uid":"my_uid","secret":"my_secret","expires":"my_expires"}
response_str = simplejson.dumps(response)
fb.auth.getSession()
args = fb._add_session_args()
def test7(self):
global response_str
response = 'abcdef'
response_str = simplejson.dumps(response)
fb = facebook.Facebook(my_api_key, my_secret_key)
fb.login = self.login
fb.auth.createToken()
self.assertEquals(str(fb.auth_token),"abcdef")
url = fb.get_authorize_url(next="next",next_cancel="next_cancel")
self.assertEquals(url,
'http://www.facebook.com/authorize.php?api_key=%s&next_cancel=next_cancel&v=1.0&next=next' % (my_api_key,))
def test8(self):
class Request:
def __init__(self,post,get,method):
self.POST = post
self.GET = get
self.method = method
global response_str
response = {"session_key":"abcdef","uid":"my_uid","secret":"my_secret","expires":"my_expires"}
response_str = simplejson.dumps(response)
req = Request({},{'installed':1,'fb_page_id':'id','auth_token':'abcdef'},'GET')
fb = facebook.Facebook(my_api_key, my_secret_key)
fb.login = self.login
res = fb.check_session(req)
self.assertTrue(res)
def test9(self):
global response_str
response = 'abcdef'
response_str = simplejson.dumps(response)
fb = facebook.Facebook(my_api_key, my_secret_key)
fb.login = self.login
fb.auth.createToken()
self.assertEquals(str(fb.auth_token),"abcdef")
url = fb.get_add_url(next="next")
self.assertEquals(url,
'http://www.facebook.com/install.php?api_key=%s&v=1.0&next=next' % (my_api_key,))
def send(self,xml):
self.xml = xml
def test10(self):
import Image
image1 = Image.new("RGB", (400, 300), (255, 255, 255))
filename = "image_file.jpg"
image1.save(filename)
global response_str
fb = facebook.Facebook(my_api_key, my_secret_key)
fb.login = self.login
facebook.httplib.HTTP = Mock('httplib.HTTP')
http_connection = Mock('http_connection')
facebook.httplib.HTTP.mock_returns = http_connection
http_connection.send.mock_returns_func = self.send
def _http_passes():
return [200,]
http_connection.getreply.mock_returns_func = _http_passes
def read():
response = {"stuff":"stuff"}
response_str = simplejson.dumps(response)
return response_str
http_connection.file.read.mock_returns_func = read
response = {"session_key":"key","uid":"my_uid","secret":"my_secret","expires":"my_expires"}
response_str = simplejson.dumps(response)
res = fb.auth.getSession()
result = fb.photos.upload(image=filename,aid="aid",caption="a caption")
self.assertEquals(str(result["stuff"]),"stuff")
os.remove(filename)
if __name__ == "__main__":
# Build the test suite
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(pyfacebook_UnitTests))
# Execute the test suite
print("Testing Proxy class\n")
result = unittest.TextTestRunner(verbosity=2).run(suite)
sys.exit(len(result.errors) + len(result.failures))
python-facebook-0.svn20100209/MANIFEST.in 0000644 0001750 0001750 00000000035 11315701561 016140 0 ustar ianw ianw recursive-include examples *
python-facebook-0.svn20100209/bin/ 0000755 0001750 0001750 00000000000 11315701561 015154 5 ustar ianw ianw python-facebook-0.svn20100209/bin/djangofb.py 0000755 0001750 0001750 00000010762 11315701561 017311 0 ustar ianw ianw #!/usr/bin/env python
if __name__ == '__main__':
import sys, os, re
def usage():
sys.stderr.write('Usage: djangofb.py startapp \n')
sys.exit(1)
if len(sys.argv) not in (2, 3):
usage()
if sys.argv[1] != 'startapp':
usage()
app_name = len(sys.argv) == 3 and sys.argv[2] or 'fbapp'
try:
sys.path.insert(0, os.getcwd())
import settings # Assumed to be in the same directory or current directory.
except ImportError:
sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r or in the current directory. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
sys.exit(1)
from django.core import management
directory = management.setup_environ(settings)
if hasattr(management, 'color'):
# Current svn version of django
from django.core.management.color import color_style
style = color_style()
else:
# Compatibility with 0.96
from django.core.management import style
project_dir = os.path.normpath(os.path.join(directory, '..'))
parent_dir = os.path.basename(project_dir)
project_name = os.path.basename(directory)
if app_name == project_name:
sys.stderr.write(style.ERROR('Error: You cannot create an app with the same name (%r) as your project.\n' % app_name))
sys.exit(1)
if app_name == 'facebook':
sys.stderr.write(style.ERROR('Error: You cannot name your app "facebook", since this can cause conflicts with imports in Python < 2.5.\n'))
sys.exit(1)
if not re.search(r'^\w+$', app_name):
sys.stderr.write(style.ERROR('Error: %r is not a valid app name. Please use only numbers, letters and underscores.\n' % (app_name)))
sys.exit(1)
top_dir = os.path.join(directory, app_name)
try:
os.mkdir(top_dir)
except OSError, e:
sys.stderr.write(style.ERROR("Error: %s\n" % e))
sys.exit(1)
import facebook
template_dir = os.path.join(facebook.__path__[0], 'djangofb', 'default_app')
sys.stderr.write('Creating Facebook application %r...\n' % app_name)
for d, subdirs, files in os.walk(template_dir):
relative_dir = d[len(template_dir) + 1:]
if relative_dir:
os.mkdir(os.path.join(top_dir, relative_dir))
subdirs[:] = [s for s in subdirs if not s.startswith('.')]
for f in files:
if f.endswith('.pyc'):
continue
path_old = os.path.join(d, f)
path_new = os.path.join(top_dir, relative_dir, f)
f_old = open(path_old, 'r')
f_new = open(path_new, 'w')
sys.stderr.write('Writing %s...\n' % path_new)
f_new.write(f_old.read().replace('{{ project }}', project_name).replace('{{ app }}', app_name))
f_new.close()
f_old.close()
sys.stderr.write('Done!\n\n')
from django.conf import settings
need_api_key = not hasattr(settings, 'FACEBOOK_API_KEY')
need_middleware = not 'facebook.djangofb.FacebookMiddleware' in settings.MIDDLEWARE_CLASSES
need_loader = not 'django.template.loaders.app_directories.load_template_source' in settings.TEMPLATE_LOADERS
need_install_app = not '%s.%s' % (project_name, app_name) in settings.INSTALLED_APPS
if need_api_key or need_middleware or need_loader or need_install_app:
sys.stderr.write("""There are a couple of things you NEED to do before you can use this app:\n\n""")
if need_api_key:
sys.stderr.write(""" * Set FACEBOOK_API_KEY and FACEBOOK_SECRET_KEY to the appropriate values in settings.py\n\n""")
if need_middleware:
sys.stderr.write(""" * Add 'facebook.djangofb.FacebookMiddleware' to your MIDDLEWARE_CLASSES in settings.py\n\n""")
if need_loader:
sys.stderr.write(""" * Add 'django.template.loaders.app_directories.load_template_source' to your TEMPLATE_LOADERS in settings.py\n\n""")
if need_install_app:
sys.stderr.write(""" * Add '%s.%s' to your INSTALLED_APPS in settings.py\n\n""" % (project_name, app_name))
sys.stderr.write("""The final step is to add (r'^%s/', include('%s.%s.urls')) to your urls.py, and then set your callback page in the application settings on Facebook to 'http://your.domain.com/%s/'.
Good luck!
""" % (project_name, project_name, app_name, project_name))