Commits

David Larlet committed a30cd24

Switching to pip's requirements for external libs (piston only required for tests)

Comments (0)

Files changed (48)

django_roa/db/models.py

 from django.utils.functional import curry, update_wrapper
 from django.utils.encoding import force_unicode, smart_unicode
 
-from libs.restkit import Resource, RequestFailed
+from restkit import Resource, RequestFailed
 from django_roa.db.exceptions import ROAException
 
 logger = logging.getLogger("django_roa")

django_roa/db/query.py

 from django.db.models.query_utils import Q
 from django.utils.encoding import force_unicode
 
-from libs.restkit import Resource, ResourceNotFound, RequestFailed
+from restkit import Resource, ResourceNotFound, RequestFailed
 from django_roa.db.exceptions import ROAException, ROANotImplementedYetException
 
 logger = logging.getLogger("django_roa")

examples/django_roa_client/tests.py

 from django.core.serializers import register_serializer
 from django.contrib.contenttypes.models import ContentType
 
-from libs.restkit import Resource
+from restkit import Resource
 from django_roa.remoteauth.models import User, Message, Group, Permission
 from django_roa_client.models import RemotePage, RemotePageWithManyFields, \
     RemotePageWithBooleanFields, RemotePageWithRelations, \

examples/django_roa_server/emitters.py

 from django.http import HttpResponse
 from django.utils import simplejson
 
-from libs.piston.emitters import Emitter, DjangoEmitter
+from piston.emitters import Emitter, DjangoEmitter
 
 logger = logging.getLogger("django_roa_server")
 

examples/django_roa_server/handlers.py

 from django.shortcuts import get_object_or_404, _get_queryset
 from django.utils.encoding import smart_unicode
 
-from libs.piston.handler import BaseHandler, AnonymousBaseHandler
-from libs.piston.utils import rc
+from piston.handler import BaseHandler, AnonymousBaseHandler
+from piston.utils import rc
 
 from django_roa_server.models import RemotePage, RemotePageWithManyFields, \
     RemotePageWithBooleanFields, RemotePageWithCustomSlug, \

examples/django_roa_server/urls.py

 from django.conf import settings
 from django.conf.urls.defaults import *
 
-from libs.piston.resource import Resource
-from libs.piston.authentication import HttpBasicAuthentication
+from piston.resource import Resource
+from piston.authentication import HttpBasicAuthentication
 
 from django_roa_server.handlers import RemotePageHandler, \
     RemotePageWithManyFieldsHandler, RemotePageWithBooleanFieldsHandler, \

libs/__init__.py

Empty file removed.

libs/piston/__init__.py

Empty file removed.

libs/piston/authentication.py

-import binascii
-
-import oauth
-from django.http import HttpResponse, HttpResponseRedirect
-from django.contrib.auth.models import User, AnonymousUser
-from django.contrib.auth.decorators import login_required
-from django.template import loader
-from django.contrib.auth import authenticate
-from django.conf import settings
-from django.core.urlresolvers import get_callable
-from django.core.exceptions import ImproperlyConfigured
-from django.shortcuts import render_to_response
-from django.template import RequestContext
-
-from libs.piston import forms
-
-class NoAuthentication(object):
-    """
-    Authentication handler that always returns
-    True, so no authentication is needed, nor
-    initiated (`challenge` is missing.)
-    """
-    def is_authenticated(self, request):
-        return True
-
-class HttpBasicAuthentication(object):
-    """
-    Basic HTTP authenticater. Synopsis:
-    
-    Authentication handlers must implement two methods:
-     - `is_authenticated`: Will be called when checking for
-        authentication. Receives a `request` object, please
-        set your `User` object on `request.user`, otherwise
-        return False (or something that evaluates to False.)
-     - `challenge`: In cases where `is_authenticated` returns
-        False, the result of this method will be returned.
-        This will usually be a `HttpResponse` object with
-        some kind of challenge headers and 401 code on it.
-    """
-    def __init__(self, auth_func=authenticate, realm='API'):
-        self.auth_func = auth_func
-        self.realm = realm
-
-    def is_authenticated(self, request):
-        auth_string = request.META.get('HTTP_AUTHORIZATION', None)
-
-        if not auth_string:
-            return False
-            
-        try:
-            (authmeth, auth) = auth_string.split(" ", 1)
-
-            if not authmeth.lower() == 'basic':
-                return False
-
-            auth = auth.strip().decode('base64')
-            (username, password) = auth.split(':', 1)
-        except (ValueError, binascii.Error):
-            return False
-        
-        request.user = self.auth_func(username=username, password=password) \
-            or AnonymousUser()
-                
-        return not request.user in (False, None, AnonymousUser())
-        
-    def challenge(self):
-        resp = HttpResponse("Authorization Required")
-        resp['WWW-Authenticate'] = 'Basic realm="%s"' % self.realm
-        resp.status_code = 401
-        return resp
-
-    def __repr__(self):
-        return u'<HTTPBasic: realm=%s>' % self.realm
-
-class HttpBasicSimple(HttpBasicAuthentication):
-    def __init__(self, realm, username, password):
-        self.user = User.objects.get(username=username)
-        self.password = password
-
-        super(HttpBasicSimple, self).__init__(auth_func=self.hash, realm=realm)
-    
-    def hash(self, username, password):
-        if username == self.user.username and password == self.password:
-            return self.user
-
-def load_data_store():
-    '''Load data store for OAuth Consumers, Tokens, Nonces and Resources
-    '''
-    path = getattr(settings, 'OAUTH_DATA_STORE', 'libs.piston.store.DataStore')
-
-    # stolen from django.contrib.auth.load_backend
-    i = path.rfind('.')
-    module, attr = path[:i], path[i+1:]
-
-    try:
-        mod = __import__(module, {}, {}, attr)
-    except ImportError, e:
-        raise ImproperlyConfigured, 'Error importing OAuth data store %s: "%s"' % (module, e)
-
-    try:
-        cls = getattr(mod, attr)
-    except AttributeError:
-        raise ImproperlyConfigured, 'Module %s does not define a "%s" OAuth data store' % (module, attr)
-
-    return cls
-
-# Set the datastore here.
-oauth_datastore = load_data_store()
-
-def initialize_server_request(request):
-    """
-    Shortcut for initialization.
-    """
-    if request.method == "POST": #and \
-#       request.META['CONTENT_TYPE'] == "application/x-www-form-urlencoded":
-        params = dict(request.REQUEST.items())
-    else:
-        params = { }
-
-    # Seems that we want to put HTTP_AUTHORIZATION into 'Authorization'
-    # for oauth.py to understand. Lovely.
-    request.META['Authorization'] = request.META.get('HTTP_AUTHORIZATION', '')
-
-    oauth_request = oauth.OAuthRequest.from_request(
-        request.method, request.build_absolute_uri(), 
-        headers=request.META, parameters=params,
-        query_string=request.environ.get('QUERY_STRING', ''))
-        
-    if oauth_request:
-        oauth_server = oauth.OAuthServer(oauth_datastore(oauth_request))
-        oauth_server.add_signature_method(oauth.OAuthSignatureMethod_PLAINTEXT())
-        oauth_server.add_signature_method(oauth.OAuthSignatureMethod_HMAC_SHA1())
-    else:
-        oauth_server = None
-        
-    return oauth_server, oauth_request
-
-def send_oauth_error(err=None):
-    """
-    Shortcut for sending an error.
-    """
-    response = HttpResponse(err.message.encode('utf-8'))
-    response.status_code = 401
-
-    realm = 'OAuth'
-    header = oauth.build_authenticate_header(realm=realm)
-
-    for k, v in header.iteritems():
-        response[k] = v
-
-    return response
-
-def oauth_request_token(request):
-    oauth_server, oauth_request = initialize_server_request(request)
-    
-    if oauth_server is None:
-        return INVALID_PARAMS_RESPONSE
-    try:
-        token = oauth_server.fetch_request_token(oauth_request)
-
-        response = HttpResponse(token.to_string())
-    except oauth.OAuthError, err:
-        response = send_oauth_error(err)
-
-    return response
-
-def oauth_auth_view(request, token, callback, params):
-    form = forms.OAuthAuthenticationForm(initial={
-        'oauth_token': token.key,
-        'oauth_callback': token.get_callback_url() or callback,
-      })
-
-    return render_to_response('piston/authorize_token.html',
-            { 'form': form }, RequestContext(request))
-
-@login_required
-def oauth_user_auth(request):
-    oauth_server, oauth_request = initialize_server_request(request)
-    
-    if oauth_request is None:
-        return INVALID_PARAMS_RESPONSE
-        
-    try:
-        token = oauth_server.fetch_request_token(oauth_request)
-    except oauth.OAuthError, err:
-        return send_oauth_error(err)
-        
-    try:
-        callback = oauth_server.get_callback(oauth_request)
-    except:
-        callback = None
-    
-    if request.method == "GET":
-        params = oauth_request.get_normalized_parameters()
-
-        oauth_view = getattr(settings, 'OAUTH_AUTH_VIEW', None)
-        if oauth_view is None:
-            return oauth_auth_view(request, token, callback, params)
-        else:
-            return get_callable(oauth_view)(request, token, callback, params)
-    elif request.method == "POST":
-        try:
-            form = forms.OAuthAuthenticationForm(request.POST)
-            if form.is_valid():
-                token = oauth_server.authorize_token(token, request.user)
-                args = '?'+token.to_string(only_key=True)
-            else:
-                args = '?error=%s' % 'Access not granted by user.'
-                print "FORM ERROR", form.errors
-            
-            if not callback:
-                callback = getattr(settings, 'OAUTH_CALLBACK_VIEW')
-                return get_callable(callback)(request, token)
-                
-            response = HttpResponseRedirect(callback+args)
-                
-        except oauth.OAuthError, err:
-            response = send_oauth_error(err)
-    else:
-        response = HttpResponse('Action not allowed.')
-            
-    return response
-
-def oauth_access_token(request):
-    oauth_server, oauth_request = initialize_server_request(request)
-    
-    if oauth_request is None:
-        return INVALID_PARAMS_RESPONSE
-        
-    try:
-        token = oauth_server.fetch_access_token(oauth_request)
-        return HttpResponse(token.to_string())
-    except oauth.OAuthError, err:
-        return send_oauth_error(err)
-
-INVALID_PARAMS_RESPONSE = send_oauth_error(oauth.OAuthError('Invalid request parameters.'))
-                
-class OAuthAuthentication(object):
-    """
-    OAuth authentication. Based on work by Leah Culver.
-    """
-    def __init__(self, realm='API'):
-        self.realm = realm
-        self.builder = oauth.build_authenticate_header
-    
-    def is_authenticated(self, request):
-        """
-        Checks whether a means of specifying authentication
-        is provided, and if so, if it is a valid token.
-        
-        Read the documentation on `HttpBasicAuthentication`
-        for more information about what goes on here.
-        """
-        if self.is_valid_request(request):
-            try:
-                consumer, token, parameters = self.validate_token(request)
-            except oauth.OAuthError, err:
-                print send_oauth_error(err)
-                return False
-
-            if consumer and token:
-                request.user = token.user
-                request.consumer = consumer
-                request.throttle_extra = token.consumer.id
-                return True
-            
-        return False
-        
-    def challenge(self):
-        """
-        Returns a 401 response with a small bit on
-        what OAuth is, and where to learn more about it.
-        
-        When this was written, browsers did not understand
-        OAuth authentication on the browser side, and hence
-        the helpful template we render. Maybe some day in the
-        future, browsers will take care of this stuff for us
-        and understand the 401 with the realm we give it.
-        """
-        response = HttpResponse()
-        response.status_code = 401
-        realm = 'API'
-
-        for k, v in self.builder(realm=realm).iteritems():
-            response[k] = v
-
-        tmpl = loader.render_to_string('oauth/challenge.html',
-            { 'MEDIA_URL': settings.MEDIA_URL })
-
-        response.content = tmpl
-
-        return response
-        
-    @staticmethod
-    def is_valid_request(request):
-        """
-        Checks whether the required parameters are either in
-        the http-authorization header sent by some clients,
-        which is by the way the preferred method according to
-        OAuth spec, but otherwise fall back to `GET` and `POST`.
-        """
-        must_have = [ 'oauth_'+s for s in [
-            'consumer_key', 'token', 'signature',
-            'signature_method', 'timestamp', 'nonce' ] ]
-        
-        is_in = lambda l: all([ (p in l) for p in must_have ])
-
-        auth_params = request.META.get("HTTP_AUTHORIZATION", "")
-        req_params = request.REQUEST
-             
-        return is_in(auth_params) or is_in(req_params)
-        
-    @staticmethod
-    def validate_token(request, check_timestamp=True, check_nonce=True):
-        oauth_server, oauth_request = initialize_server_request(request)
-        return oauth_server.verify_request(oauth_request)
-

libs/piston/decorator.py

-"""
-Decorator module, see
-http://www.phyast.pitt.edu/~micheles/python/documentation.html
-for the documentation and below for the licence.
-"""
-
-## The basic trick is to generate the source code for the decorated function
-## with the right signature and to evaluate it.
-## Uncomment the statement 'print >> sys.stderr, func_src'  in _decorator
-## to understand what is going on.
-
-__all__ = ["decorator", "new_wrapper", "getinfo"]
-
-import inspect, sys
-
-try:
-    set
-except NameError:
-    from sets import Set as set
-
-def getinfo(func):
-    """
-    Returns an info dictionary containing:
-    - name (the name of the function : str)
-    - argnames (the names of the arguments : list)
-    - defaults (the values of the default arguments : tuple)
-    - signature (the signature : str)
-    - doc (the docstring : str)
-    - module (the module name : str)
-    - dict (the function __dict__ : str)
-    
-    >>> def f(self, x=1, y=2, *args, **kw): pass
-
-    >>> info = getinfo(f)
-
-    >>> info["name"]
-    'f'
-    >>> info["argnames"]
-    ['self', 'x', 'y', 'args', 'kw']
-    
-    >>> info["defaults"]
-    (1, 2)
-
-    >>> info["signature"]
-    'self, x, y, *args, **kw'
-    """
-    assert inspect.ismethod(func) or inspect.isfunction(func)
-    regargs, varargs, varkwargs, defaults = inspect.getargspec(func)
-    argnames = list(regargs)
-    if varargs:
-        argnames.append(varargs)
-    if varkwargs:
-        argnames.append(varkwargs)
-    signature = inspect.formatargspec(regargs, varargs, varkwargs, defaults,
-                                      formatvalue=lambda value: "")[1:-1]
-    return dict(name=func.__name__, argnames=argnames, signature=signature,
-                defaults = func.func_defaults, doc=func.__doc__,
-                module=func.__module__, dict=func.__dict__,
-                globals=func.func_globals, closure=func.func_closure)
-
-# akin to functools.update_wrapper
-def update_wrapper(wrapper, model, infodict=None):
-    infodict = infodict or getinfo(model)
-    try:
-        wrapper.__name__ = infodict['name']
-    except: # Python version < 2.4
-        pass
-    wrapper.__doc__ = infodict['doc']
-    wrapper.__module__ = infodict['module']
-    wrapper.__dict__.update(infodict['dict'])
-    wrapper.func_defaults = infodict['defaults']
-    wrapper.undecorated = model
-    return wrapper
-
-def new_wrapper(wrapper, model):
-    """
-    An improvement over functools.update_wrapper. The wrapper is a generic
-    callable object. It works by generating a copy of the wrapper with the 
-    right signature and by updating the copy, not the original.
-    Moreovoer, 'model' can be a dictionary with keys 'name', 'doc', 'module',
-    'dict', 'defaults'.
-    """
-    if isinstance(model, dict):
-        infodict = model
-    else: # assume model is a function
-        infodict = getinfo(model)
-    assert not '_wrapper_' in infodict["argnames"], (
-        '"_wrapper_" is a reserved argument name!')
-    src = "lambda %(signature)s: _wrapper_(%(signature)s)" % infodict
-    funcopy = eval(src, dict(_wrapper_=wrapper))
-    return update_wrapper(funcopy, model, infodict)
-
-# helper used in decorator_factory
-def __call__(self, func):
-    infodict = getinfo(func)
-    for name in ('_func_', '_self_'):
-        assert not name in infodict["argnames"], (
-           '%s is a reserved argument name!' % name)
-    src = "lambda %(signature)s: _self_.call(_func_, %(signature)s)"
-    new = eval(src % infodict, dict(_func_=func, _self_=self))
-    return update_wrapper(new, func, infodict)
-
-def decorator_factory(cls):
-    """
-    Take a class with a ``.caller`` method and return a callable decorator
-    object. It works by adding a suitable __call__ method to the class;
-    it raises a TypeError if the class already has a nontrivial __call__
-    method.
-    """
-    attrs = set(dir(cls))
-    if '__call__' in attrs:
-        raise TypeError('You cannot decorate a class with a nontrivial '
-                        '__call__ method')
-    if 'call' not in attrs:
-        raise TypeError('You cannot decorate a class without a '
-                        '.call method')
-    cls.__call__ = __call__
-    return cls
-
-def decorator(caller):
-    """
-    General purpose decorator factory: takes a caller function as
-    input and returns a decorator with the same attributes.
-    A caller function is any function like this::
-
-     def caller(func, *args, **kw):
-         # do something
-         return func(*args, **kw)
-    
-    Here is an example of usage:
-
-    >>> @decorator
-    ... def chatty(f, *args, **kw):
-    ...     print "Calling %r" % f.__name__
-    ...     return f(*args, **kw)
-
-    >>> chatty.__name__
-    'chatty'
-    
-    >>> @chatty
-    ... def f(): pass
-    ...
-    >>> f()
-    Calling 'f'
-
-    decorator can also take in input a class with a .caller method; in this
-    case it converts the class into a factory of callable decorator objects.
-    See the documentation for an example.
-    """
-    if inspect.isclass(caller):
-        return decorator_factory(caller)
-    def _decorator(func): # the real meat is here
-        infodict = getinfo(func)
-        argnames = infodict['argnames']
-        assert not ('_call_' in argnames or '_func_' in argnames), (
-            'You cannot use _call_ or _func_ as argument names!')
-        src = "lambda %(signature)s: _call_(_func_, %(signature)s)" % infodict
-        # import sys; print >> sys.stderr, src # for debugging purposes
-        dec_func = eval(src, dict(_func_=func, _call_=caller))
-        return update_wrapper(dec_func, func, infodict)
-    return update_wrapper(_decorator, caller)
-
-if __name__ == "__main__":
-    import doctest; doctest.testmod()
-
-##########################     LEGALESE    ###############################
-      
-##   Redistributions of source code must retain the above copyright 
-##   notice, this list of conditions and the following disclaimer.
-##   Redistributions in bytecode 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. 
-
-##   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT
-##   HOLDERS 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.

libs/piston/doc.py

-import inspect, handler
-
-from libs.piston.handler import typemapper
-from libs.piston.handler import handler_tracker
-
-from django.core.urlresolvers import get_resolver, get_callable, get_script_prefix
-from django.shortcuts import render_to_response
-from django.template import RequestContext
-
-def generate_doc(handler_cls):
-    """
-    Returns a `HandlerDocumentation` object
-    for the given handler. Use this to generate
-    documentation for your API.
-    """
-    if not type(handler_cls) is handler.HandlerMetaClass:
-        raise ValueError("Give me handler, not %s" % type(handler_cls))
-        
-    return HandlerDocumentation(handler_cls)
-    
-class HandlerMethod(object):
-    def __init__(self, method, stale=False):
-        self.method = method
-        self.stale = stale
-        
-    def iter_args(self):
-        args, _, _, defaults = inspect.getargspec(self.method)
-
-        for idx, arg in enumerate(args):
-            if arg in ('self', 'request', 'form'):
-                continue
-
-            didx = len(args)-idx
-
-            if defaults and len(defaults) >= didx:
-                yield (arg, str(defaults[-didx]))
-            else:
-                yield (arg, None)
-        
-    @property
-    def signature(self, parse_optional=True):
-        spec = ""
-
-        for argn, argdef in self.iter_args():
-            spec += argn
-            
-            if argdef:
-                spec += '=%s' % argdef
-            
-            spec += ', '
-            
-        spec = spec.rstrip(", ")
-        
-        if parse_optional:
-            return spec.replace("=None", "=<optional>")
-            
-        return spec
-        
-    @property
-    def doc(self):
-        return inspect.getdoc(self.method)
-    
-    @property
-    def name(self):
-        return self.method.__name__
-    
-    @property
-    def http_name(self):
-        if self.name == 'read':
-            return 'GET'
-        elif self.name == 'create':
-            return 'POST'
-        elif self.name == 'delete':
-            return 'DELETE'
-        elif self.name == 'update':
-            return 'PUT'
-    
-    def __repr__(self):
-        return "<Method: %s>" % self.name
-    
-class HandlerDocumentation(object):
-    def __init__(self, handler):
-        self.handler = handler
-        
-    def get_methods(self, include_default=False):
-        for method in "read create update delete".split():
-            met = getattr(self.handler, method, None)
-
-            if not met:
-                continue
-                
-            stale = inspect.getmodule(met) is handler
-
-            if not self.handler.is_anonymous:
-                if met and (not stale or include_default):
-                    yield HandlerMethod(met, stale)
-            else:
-                if not stale or met.__name__ == "read" \
-                    and 'GET' in self.allowed_methods:
-                    
-                    yield HandlerMethod(met, stale)
-        
-    def get_all_methods(self):
-        return self.get_methods(include_default=True)
-        
-    @property
-    def is_anonymous(self):
-        return handler.is_anonymous
-
-    def get_model(self):
-        return getattr(self, 'model', None)
-            
-    @property
-    def has_anonymous(self):
-        return self.handler.anonymous
-            
-    @property
-    def anonymous(self):
-        if self.has_anonymous:
-            return HandlerDocumentation(self.handler.anonymous)
-            
-    @property
-    def doc(self):
-        return self.handler.__doc__
-    
-    @property
-    def name(self):
-        return self.handler.__name__
-    
-    @property
-    def allowed_methods(self):
-        return self.handler.allowed_methods
-    
-    def get_resource_uri_template(self):
-        """
-        URI template processor.
-        
-        See http://bitworking.org/projects/URI-Templates/
-        """
-        def _convert(template, params=[]):
-            """URI template converter"""
-            paths = template % dict([p, "{%s}" % p] for p in params)
-            return u'%s%s' % (get_script_prefix(), paths)
-        
-        try:
-            resource_uri = self.handler.resource_uri()
-            
-            components = [None, [], {}]
-
-            for i, value in enumerate(resource_uri):
-                components[i] = value
-        
-            lookup_view, args, kwargs = components
-            lookup_view = get_callable(lookup_view, True)
-
-            possibilities = get_resolver(None).reverse_dict.getlist(lookup_view)
-            
-            for possibility, pattern in possibilities:
-                for result, params in possibility:
-                    if args:
-                        if len(args) != len(params):
-                            continue
-                        return _convert(result, params)
-                    else:
-                        if set(kwargs.keys()) != set(params):
-                            continue
-                        return _convert(result, params)
-        except:
-            return None
-        
-    resource_uri_template = property(get_resource_uri_template)
-    
-    def __repr__(self):
-        return u'<Documentation for "%s">' % self.name
-
-def documentation_view(request):
-    """
-    Generic documentation view. Generates documentation
-    from the handlers you've defined.
-    """
-    docs = [ ]
-
-    for handler in handler_tracker: 
-        docs.append(generate_doc(handler))
-
-    def _compare(doc1, doc2): 
-       #handlers and their anonymous counterparts are put next to each other.
-       name1 = doc1.name.replace("Anonymous", "")
-       name2 = doc2.name.replace("Anonymous", "")
-       return cmp(name1, name2)    
- 
-    docs.sort(_compare)
-       
-    return render_to_response('documentation.html', 
-        { 'docs': docs }, RequestContext(request))

libs/piston/emitters.py

-from __future__ import generators
-
-import decimal, re, inspect
-import copy
-
-try:
-    # yaml isn't standard with python.  It shouldn't be required if it
-    # isn't used.
-    import yaml
-except ImportError:
-    yaml = None
-
-# Fallback since `any` isn't in Python <2.5
-try:
-    any
-except NameError:
-    def any(iterable):
-        for element in iterable:
-            if element:
-                return True
-        return False
-
-from django.db.models.query import QuerySet
-from django.db.models import Model, permalink
-from django.utils import simplejson
-from django.utils.xmlutils import SimplerXMLGenerator
-from django.utils.encoding import smart_unicode
-from django.core.urlresolvers import reverse, NoReverseMatch
-from django.core.serializers.json import DateTimeAwareJSONEncoder
-from django.http import HttpResponse
-from django.core import serializers
-
-from utils import HttpStatusCode, Mimer
-from validate_jsonp import is_valid_jsonp_callback_value
-
-try:
-    import cStringIO as StringIO
-except ImportError:
-    import StringIO
-
-try:
-    import cPickle as pickle
-except ImportError:
-    import pickle
-
-# Allow people to change the reverser (default `permalink`).
-reverser = permalink
-
-class Emitter(object):
-    """
-    Super emitter. All other emitters should subclass
-    this one. It has the `construct` method which
-    conveniently returns a serialized `dict`. This is
-    usually the only method you want to use in your
-    emitter. See below for examples.
-
-    `RESERVED_FIELDS` was introduced when better resource
-    method detection came, and we accidentially caught these
-    as the methods on the handler. Issue58 says that's no good.
-    """
-    EMITTERS = { }
-    RESERVED_FIELDS = set([ 'read', 'update', 'create', 
-                            'delete', 'model', 'anonymous',
-                            'allowed_methods', 'fields', 'exclude' ])
-
-    def __init__(self, payload, typemapper, handler, fields=(), anonymous=True):
-        self.typemapper = typemapper
-        self.data = payload
-        self.handler = handler
-        self.fields = fields
-        self.anonymous = anonymous
-        
-        if isinstance(self.data, Exception):
-            raise
-    
-    def method_fields(self, handler, fields):
-        if not handler:
-            return { }
-
-        ret = dict()
-            
-        for field in fields - Emitter.RESERVED_FIELDS:
-            t = getattr(handler, str(field), None)
-
-            if t and callable(t):
-                ret[field] = t
-
-        return ret
-    
-    def construct(self):
-        """
-        Recursively serialize a lot of types, and
-        in cases where it doesn't recognize the type,
-        it will fall back to Django's `smart_unicode`.
-        
-        Returns `dict`.
-        """
-        def _any(thing, fields=()):
-            """
-            Dispatch, all types are routed through here.
-            """
-            ret = None
-            
-            if isinstance(thing, QuerySet):
-                ret = _qs(thing, fields=fields)
-            elif isinstance(thing, (tuple, list)):
-                ret = _list(thing)
-            elif isinstance(thing, dict):
-                ret = _dict(thing)
-            elif isinstance(thing, decimal.Decimal):
-                ret = str(thing)
-            elif isinstance(thing, Model):
-                ret = _model(thing, fields=fields)
-            elif isinstance(thing, HttpResponse):
-                raise HttpStatusCode(thing)
-            elif inspect.isfunction(thing):
-                if not inspect.getargspec(thing)[0]:
-                    ret = _any(thing())
-            elif hasattr(thing, '__emittable__'):
-                f = thing.__emittable__
-                if inspect.ismethod(f) and len(inspect.getargspec(f)[0]) == 1:
-                    ret = _any(f())
-            elif repr(thing).startswith("<django.db.models.fields.related.RelatedManager"):
-                ret = _any(thing.all())
-            else:
-                ret = smart_unicode(thing, strings_only=True)
-
-            return ret
-
-        def _fk(data, field):
-            """
-            Foreign keys.
-            """
-            return _any(getattr(data, field.name))
-        
-        def _related(data, fields=()):
-            """
-            Foreign keys.
-            """
-            return [ _model(m, fields) for m in data.iterator() ]
-        
-        def _m2m(data, field, fields=()):
-            """
-            Many to many (re-route to `_model`.)
-            """
-            return [ _model(m, fields) for m in getattr(data, field.name).iterator() ]
-        
-        def _model(data, fields=()):
-            """
-            Models. Will respect the `fields` and/or
-            `exclude` on the handler (see `typemapper`.)
-            """
-            ret = { }
-            handler = self.in_typemapper(type(data), self.anonymous)
-            get_absolute_uri = False
-            
-            if handler or fields:
-                v = lambda f: getattr(data, f.attname)
-
-                if not fields:
-                    """
-                    Fields was not specified, try to find teh correct
-                    version in the typemapper we were sent.
-                    """
-                    mapped = self.in_typemapper(type(data), self.anonymous)
-                    get_fields = set(mapped.fields)
-                    exclude_fields = set(mapped.exclude).difference(get_fields)
-
-                    if 'absolute_uri' in get_fields:
-                        get_absolute_uri = True
-                
-                    if not get_fields:
-                        get_fields = set([ f.attname.replace("_id", "", 1)
-                            for f in data._meta.fields ])
-                
-                    # sets can be negated.
-                    for exclude in exclude_fields:
-                        if isinstance(exclude, basestring):
-                            get_fields.discard(exclude)
-                            
-                        elif isinstance(exclude, re._pattern_type):
-                            for field in get_fields.copy():
-                                if exclude.match(field):
-                                    get_fields.discard(field)
-                                    
-                else:
-                    get_fields = set(fields)
-
-                met_fields = self.method_fields(handler, get_fields)
-                           
-                for f in data._meta.local_fields:
-                    if f.serialize and not any([ p in met_fields for p in [ f.attname, f.name ]]):
-                        if not f.rel:
-                            if f.attname in get_fields:
-                                ret[f.attname] = _any(v(f))
-                                get_fields.remove(f.attname)
-                        else:
-                            if f.attname[:-3] in get_fields:
-                                ret[f.name] = _fk(data, f)
-                                get_fields.remove(f.name)
-                
-                for mf in data._meta.many_to_many:
-                    if mf.serialize and mf.attname not in met_fields:
-                        if mf.attname in get_fields:
-                            ret[mf.name] = _m2m(data, mf)
-                            get_fields.remove(mf.name)
-                
-                # try to get the remainder of fields
-                for maybe_field in get_fields:
-                    if isinstance(maybe_field, (list, tuple)):
-                        model, fields = maybe_field
-                        inst = getattr(data, model, None)
-
-                        if inst:
-                            if hasattr(inst, 'all'):
-                                ret[model] = _related(inst, fields)
-                            elif callable(inst):
-                                if len(inspect.getargspec(inst)[0]) == 1:
-                                    ret[model] = _any(inst(), fields)
-                            else:
-                                ret[model] = _model(inst, fields)
-
-                    elif maybe_field in met_fields:
-                        # Overriding normal field which has a "resource method"
-                        # so you can alter the contents of certain fields without
-                        # using different names.
-                        ret[maybe_field] = _any(met_fields[maybe_field](data))
-
-                    else:                    
-                        maybe = getattr(data, maybe_field, None)
-                        if maybe:
-                            if callable(maybe):
-                                if len(inspect.getargspec(maybe)[0]) == 1:
-                                    ret[maybe_field] = _any(maybe())
-                            else:
-                                ret[maybe_field] = _any(maybe)
-                        else:
-                            handler_f = getattr(handler or self.handler, maybe_field, None)
-
-                            if handler_f:
-                                ret[maybe_field] = _any(handler_f(data))
-
-            else:
-                for f in data._meta.fields:
-                    ret[f.attname] = _any(getattr(data, f.attname))
-                
-                fields = dir(data.__class__) + ret.keys()
-                add_ons = [k for k in dir(data) if k not in fields]
-                
-                for k in add_ons:
-                    ret[k] = _any(getattr(data, k))
-            
-            # resouce uri
-            if self.in_typemapper(type(data), self.anonymous):
-                handler = self.in_typemapper(type(data), self.anonymous)
-                if hasattr(handler, 'resource_uri'):
-                    url_id, fields = handler.resource_uri(data)
-
-                    try:
-                        ret['resource_uri'] = reverser( lambda: (url_id, fields) )()
-                    except NoReverseMatch, e:
-                        pass
-            
-            if hasattr(data, 'get_api_url') and 'resource_uri' not in ret:
-                try: ret['resource_uri'] = data.get_api_url()
-                except: pass
-            
-            # absolute uri
-            if hasattr(data, 'get_absolute_url') and get_absolute_uri:
-                try: ret['absolute_uri'] = data.get_absolute_url()
-                except: pass
-            
-            return ret
-        
-        def _qs(data, fields=()):
-            """
-            Querysets.
-            """
-            return [ _any(v, fields) for v in data ]
-                
-        def _list(data):
-            """
-            Lists.
-            """
-            return [ _any(v) for v in data ]
-            
-        def _dict(data):
-            """
-            Dictionaries.
-            """
-            return dict([ (k, _any(v)) for k, v in data.iteritems() ])
-            
-        # Kickstart the seralizin'.
-        return _any(self.data, self.fields)
-    
-    def in_typemapper(self, model, anonymous):
-        for klass, (km, is_anon) in self.typemapper.iteritems():
-            if model is km and is_anon is anonymous:
-                return klass
-        
-    def render(self):
-        """
-        This super emitter does not implement `render`,
-        this is a job for the specific emitter below.
-        """
-        raise NotImplementedError("Please implement render.")
-        
-    def stream_render(self, request, stream=True):
-        """
-        Tells our patched middleware not to look
-        at the contents, and returns a generator
-        rather than the buffered string. Should be
-        more memory friendly for large datasets.
-        """
-        yield self.render(request)
-        
-    @classmethod
-    def get(cls, format):
-        """
-        Gets an emitter, returns the class and a content-type.
-        """
-        if cls.EMITTERS.has_key(format):
-            return cls.EMITTERS.get(format)
-
-        raise ValueError("No emitters found for type %s" % format)
-    
-    @classmethod
-    def register(cls, name, klass, content_type='text/plain'):
-        """
-        Register an emitter.
-        
-        Parameters::
-         - `name`: The name of the emitter ('json', 'xml', 'yaml', ...)
-         - `klass`: The emitter class.
-         - `content_type`: The content type to serve response as.
-        """
-        cls.EMITTERS[name] = (klass, content_type)
-        
-    @classmethod
-    def unregister(cls, name):
-        """
-        Remove an emitter from the registry. Useful if you don't
-        want to provide output in one of the built-in emitters.
-        """
-        return cls.EMITTERS.pop(name, None)
-    
-class XMLEmitter(Emitter):
-    def _to_xml(self, xml, data):
-        if isinstance(data, (list, tuple)):
-            for item in data:
-                xml.startElement("resource", {})
-                self._to_xml(xml, item)
-                xml.endElement("resource")
-        elif isinstance(data, dict):
-            for key, value in data.iteritems():
-                xml.startElement(key, {})
-                self._to_xml(xml, value)
-                xml.endElement(key)
-        else:
-            xml.characters(smart_unicode(data))
-
-    def render(self, request):
-        stream = StringIO.StringIO()
-        
-        xml = SimplerXMLGenerator(stream, "utf-8")
-        xml.startDocument()
-        xml.startElement("response", {})
-        
-        self._to_xml(xml, self.construct())
-        
-        xml.endElement("response")
-        xml.endDocument()
-        
-        return stream.getvalue()
-
-Emitter.register('xml', XMLEmitter, 'text/xml; charset=utf-8')
-Mimer.register(lambda *a: None, ('text/xml',))
-
-class JSONEmitter(Emitter):
-    """
-    JSON emitter, understands timestamps.
-    """
-    def render(self, request):
-        cb = request.GET.get('callback', None)
-        seria = simplejson.dumps(self.construct(), cls=DateTimeAwareJSONEncoder, ensure_ascii=False, indent=4)
-
-        # Callback
-        if cb and is_valid_jsonp_callback_value(cb):
-            return '%s(%s)' % (cb, seria)
-
-        return seria
-    
-Emitter.register('json', JSONEmitter, 'application/json; charset=utf-8')
-Mimer.register(simplejson.loads, ('application/json',))
-    
-class YAMLEmitter(Emitter):
-    """
-    YAML emitter, uses `safe_dump` to omit the
-    specific types when outputting to non-Python.
-    """
-    def render(self, request):
-        return yaml.safe_dump(self.construct())
-
-if yaml:  # Only register yaml if it was import successfully.
-    Emitter.register('yaml', YAMLEmitter, 'application/x-yaml; charset=utf-8')
-    Mimer.register(lambda s: dict(yaml.load(s)), ('application/x-yaml',))
-
-class PickleEmitter(Emitter):
-    """
-    Emitter that returns Python pickled.
-    """
-    def render(self, request):
-        return pickle.dumps(self.construct())
-        
-Emitter.register('pickle', PickleEmitter, 'application/python-pickle')
-
-"""
-WARNING: Accepting arbitrary pickled data is a huge security concern.
-The unpickler has been disabled by default now, and if you want to use
-it, please be aware of what implications it will have.
-
-Read more: http://nadiana.com/python-pickle-insecure
-
-Uncomment the line below to enable it. You're doing so at your own risk.
-"""
-# Mimer.register(pickle.loads, ('application/python-pickle',))
-
-class DjangoEmitter(Emitter):
-    """
-    Emitter for the Django serialized format.
-    """
-    def render(self, request, format='xml'):
-        if isinstance(self.data, HttpResponse):
-            return self.data
-        elif isinstance(self.data, (int, str)):
-            response = self.data
-        else:
-            response = serializers.serialize(format, self.data, indent=True)
-
-        return response
-        
-Emitter.register('django', DjangoEmitter, 'text/xml; charset=utf-8')

libs/piston/fixtures/models.json

-[
-    {
-        "pk": 2, 
-        "model": "auth.user", 
-        "fields": {
-            "username": "pistontestuser", 
-            "first_name": "Piston", 
-            "last_name": "User", 
-            "is_active": true, 
-            "is_superuser": false, 
-            "is_staff": false, 
-            "last_login": "2009-08-03 13:11:53", 
-            "groups": [], 
-            "user_permissions": [], 
-            "password": "sha1$b6c1f$83d5879f3854f6e9d27f393e3bcb4b8db05cf671", 
-            "email": "pistontestuser@example.com", 
-            "date_joined": "2009-08-03 13:11:53"
-        }
-    },
-    {
-        "pk": 3, 
-        "model": "auth.user", 
-        "fields": {
-            "username": "pistontestconsumer", 
-            "first_name": "Piston", 
-            "last_name": "Consumer", 
-            "is_active": true, 
-            "is_superuser": false, 
-            "is_staff": false, 
-            "last_login": "2009-08-03 13:11:53", 
-            "groups": [], 
-            "user_permissions": [], 
-            "password": "sha1$b6c1f$83d5879f3854f6e9d27f393e3bcb4b8db05cf671", 
-            "email": "pistontestconsumer@example.com", 
-            "date_joined": "2009-08-03 13:11:53"
-        }
-    },
-    {
-        "pk": 1, 
-        "model": "sites.site", 
-        "fields": {
-            "domain": "example.com", 
-            "name": "example.com"
-        }
-    }
-]

libs/piston/fixtures/oauth.json

-[
-    {
-        "pk": 1, 
-        "model": "piston.consumer", 
-        "fields": {
-            "status": "accepted", 
-            "name": "Piston Test Consumer", 
-            "secret": "T5XkNMkcjffDpC9mNQJbyQnJXGsenYbz", 
-            "user": 2, 
-            "key": "8aZSFj3W54h8J8sCpx", 
-            "description": "A test consumer record for Piston unit tests."
-        }
-    },
-    {
-        "pk": 1, 
-        "model": "piston.token", 
-        "fields": {
-            "is_approved": true, 
-            "timestamp": 1249347414, 
-            "token_type": 2, 
-            "secret": "qSWZq36t7yvkBquetYBkd8JxnuCu9jKk", 
-            "user": 2, 
-            "key": "Y7358vL5hDBbeP3HHL", 
-            "consumer": 1
-        }
-    }
-]

libs/piston/forms.py

-import hmac, base64
-
-from django import forms
-from django.conf import settings
-
-class Form(forms.Form):
-    pass
-    
-class ModelForm(forms.ModelForm):
-    """
-    Subclass of `forms.ModelForm` which makes sure
-    that the initial values are present in the form
-    data, so you don't have to send all old values
-    for the form to actually validate. Django does not
-    do this on its own, which is really annoying.
-    """
-    def merge_from_initial(self):
-        self.data._mutable = True
-        filt = lambda v: v not in self.data.keys()
-        for field in filter(filt, getattr(self.Meta, 'fields', ())):
-            self.data[field] = self.initial.get(field, None)
-
-
-class OAuthAuthenticationForm(forms.Form):
-    oauth_token = forms.CharField(widget=forms.HiddenInput)
-    oauth_callback = forms.CharField(widget=forms.HiddenInput, required=False)
-    authorize_access = forms.BooleanField(required=True)
-    csrf_signature = forms.CharField(widget=forms.HiddenInput)
-
-    def __init__(self, *args, **kwargs):
-        forms.Form.__init__(self, *args, **kwargs)
-
-        self.fields['csrf_signature'].initial = self.initial_csrf_signature
-
-    def clean_csrf_signature(self):
-        sig = self.cleaned_data['csrf_signature']
-        token = self.cleaned_data['oauth_token']
-
-        sig1 = OAuthAuthenticationForm.get_csrf_signature(settings.SECRET_KEY, token)
-
-        if sig != sig1:
-            raise forms.ValidationError("CSRF signature is not valid")
-
-        return sig
-
-    def initial_csrf_signature(self):
-        token = self.initial['oauth_token']
-        return OAuthAuthenticationForm.get_csrf_signature(settings.SECRET_KEY, token)
-
-    @staticmethod
-    def get_csrf_signature(key, token):
-        # Check signature...
-        try:
-            import hashlib # 2.5
-            hashed = hmac.new(key, token, hashlib.sha1)
-        except:
-            import sha # deprecated
-            hashed = hmac.new(key, token, sha)
-
-        # calculate the digest base 64
-        return base64.b64encode(hashed.digest())
-

libs/piston/handler.py

-import warnings
-
-from utils import rc
-from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
-from django.conf import settings
-
-typemapper = { }
-handler_tracker = [ ]
-
-class HandlerMetaClass(type):
-    """
-    Metaclass that keeps a registry of class -> handler
-    mappings.
-    """
-    def __new__(cls, name, bases, attrs):
-        new_cls = type.__new__(cls, name, bases, attrs)
-
-        def already_registered(model, anon):
-            for k, (m, a) in typemapper.iteritems():
-                if model == m and anon == a:
-                    return k
-
-        if hasattr(new_cls, 'model'):
-            if already_registered(new_cls.model, new_cls.is_anonymous):
-                if not getattr(settings, 'PISTON_IGNORE_DUPE_MODELS', False):
-                    warnings.warn("Handler already registered for model %s, "
-                        "you may experience inconsistent results." % new_cls.model.__name__)
-
-            typemapper[new_cls] = (new_cls.model, new_cls.is_anonymous)
-        else:
-            typemapper[new_cls] = (None, new_cls.is_anonymous)
-
-        if name not in ('BaseHandler', 'AnonymousBaseHandler'):
-            handler_tracker.append(new_cls)
-
-        return new_cls
-
-class BaseHandler(object):
-    """
-    Basehandler that gives you CRUD for free.
-    You are supposed to subclass this for specific
-    functionality.
-
-    All CRUD methods (`read`/`update`/`create`/`delete`)
-    receive a request as the first argument from the
-    resource. Use this for checking `request.user`, etc.
-    """
-    __metaclass__ = HandlerMetaClass
-
-    allowed_methods = ('GET', 'POST', 'PUT', 'DELETE')
-    anonymous = is_anonymous = False
-    exclude = ( 'id', )
-    fields =  ( )
-
-    def flatten_dict(self, dct):
-        return dict([ (str(k), dct.get(k)) for k in dct.keys() ])
-
-    def has_model(self):
-        return hasattr(self, 'model') or hasattr(self, 'queryset')
-
-    def queryset(self, request):
-        return self.model.objects.all()
-
-    def value_from_tuple(tu, name):
-        for int_, n in tu:
-            if n == name:
-                return int_
-        return None
-
-    def exists(self, **kwargs):
-        if not self.has_model():
-            raise NotImplementedError
-
-        try:
-            self.model.objects.get(**kwargs)
-            return True
-        except self.model.DoesNotExist:
-            return False
-
-    def read(self, request, *args, **kwargs):
-        if not self.has_model():
-            return rc.NOT_IMPLEMENTED
-
-        pkfield = self.model._meta.pk.name
-
-        if pkfield in kwargs:
-            try:
-                return self.queryset(request).get(pk=kwargs.get(pkfield))
-            except ObjectDoesNotExist:
-                return rc.NOT_FOUND
-            except MultipleObjectsReturned: # should never happen, since we're using a PK
-                return rc.BAD_REQUEST
-        else:
-            return self.queryset(request).filter(*args, **kwargs)
-
-    def create(self, request, *args, **kwargs):
-        if not self.has_model():
-            return rc.NOT_IMPLEMENTED
-
-        attrs = self.flatten_dict(request.data)
-
-        try:
-            inst = self.queryset(request).get(**attrs)
-            return rc.DUPLICATE_ENTRY
-        except self.model.DoesNotExist:
-            inst = self.model(**attrs)
-            inst.save()
-            return inst
-        except self.model.MultipleObjectsReturned:
-            return rc.DUPLICATE_ENTRY
-
-    def update(self, request, *args, **kwargs):
-        if not self.has_model():
-            return rc.NOT_IMPLEMENTED
-
-        pkfield = self.model._meta.pk.name
-
-        if pkfield not in kwargs:
-            # No pk was specified
-            return rc.BAD_REQUEST
-
-        try:
-            inst = self.queryset(request).get(pk=kwargs.get(pkfield))
-        except ObjectDoesNotExist:
-            return rc.NOT_FOUND
-        except MultipleObjectsReturned: # should never happen, since we're using a PK
-            return rc.BAD_REQUEST
-
-        attrs = self.flatten_dict(request.data)
-        for k,v in attrs.iteritems():
-            setattr( inst, k, v )
-
-        inst.save()
-        return rc.ALL_OK
-
-    def delete(self, request, *args, **kwargs):
-        if not self.has_model():
-            raise NotImplementedError
-
-        try:
-            inst = self.queryset(request).get(*args, **kwargs)
-
-            inst.delete()
-
-            return rc.DELETED
-        except self.model.MultipleObjectsReturned:
-            return rc.DUPLICATE_ENTRY
-        except self.model.DoesNotExist:
-            return rc.NOT_HERE
-
-class AnonymousBaseHandler(BaseHandler):
-    """
-    Anonymous handler.
-    """
-    is_anonymous = True
-    allowed_methods = ('GET',)

libs/piston/managers.py

-from django.db import models
-from django.contrib.auth.models import User
-
-KEY_SIZE = 18
-SECRET_SIZE = 32
-
-class KeyManager(models.Manager):
-    '''Add support for random key/secret generation
-    '''
-    def generate_random_codes(self):
-        key = User.objects.make_random_password(length=KEY_SIZE)
-        secret = User.objects.make_random_password(length=SECRET_SIZE)
-
-        while self.filter(key__exact=key, secret__exact=secret).count():
-            secret = User.objects.make_random_password(length=SECRET_SIZE)
-
-        return key, secret
-
-
-class ConsumerManager(KeyManager):
-    def create_consumer(self, name, description=None, user=None):
-        """
-        Shortcut to create a consumer with random key/secret.
-        """
-        consumer, created = self.get_or_create(name=name)
-
-        if user:
-            consumer.user = user
-
-        if description:
-            consumer.description = description
-
-        if created:
-            consumer.key, consumer.secret = self.generate_random_codes()
-            consumer.save()
-
-        return consumer
-
-    _default_consumer = None
-
-class ResourceManager(models.Manager):
-    _default_resource = None
-
-    def get_default_resource(self, name):
-        """
-        Add cache if you use a default resource.
-        """
-        if not self._default_resource:
-            self._default_resource = self.get(name=name)
-
-        return self._default_resource        
-
-class TokenManager(KeyManager):
-    def create_token(self, consumer, token_type, timestamp, user=None):
-        """
-        Shortcut to create a token with random key/secret.
-        """
-        token, created = self.get_or_create(consumer=consumer, 
-                                            token_type=token_type, 
-                                            timestamp=timestamp,
-                                            user=user)
-
-        if created:
-            token.key, token.secret = self.generate_random_codes()
-            token.save()
-
-        return token
-        

libs/piston/middleware.py

-from django.middleware.http import ConditionalGetMiddleware
-from django.middleware.common import CommonMiddleware
-
-def compat_middleware_factory(klass):
-    """
-    Class wrapper that only executes `process_response`
-    if `streaming` is not set on the `HttpResponse` object.
-    Django has a bad habbit of looking at the content,
-    which will prematurely exhaust the data source if we're
-    using generators or buffers.
-    """
-    class compatwrapper(klass):
-        def process_response(self, req, resp):
-            if not hasattr(resp, 'streaming'):
-                return klass.process_response(self, req, resp)
-            return resp
-    return compatwrapper
-
-ConditionalMiddlewareCompatProxy = compat_middleware_factory(ConditionalGetMiddleware)
-CommonMiddlewareCompatProxy = compat_middleware_factory(CommonMiddleware)

libs/piston/models.py

-import urllib, time, urlparse
-
-# Django imports
-from django.db.models.signals import post_save, post_delete
-from django.db import models
-from django.contrib.auth.models import User
-from django.contrib import admin
-from django.core.mail import send_mail, mail_admins
-
-# Piston imports
-from managers import TokenManager, ConsumerManager, ResourceManager
-from signals import consumer_post_save, consumer_post_delete
-
-KEY_SIZE = 18
-SECRET_SIZE = 32
-VERIFIER_SIZE = 10
-
-CONSUMER_STATES = (
-    ('pending', 'Pending'),
-    ('accepted', 'Accepted'),
-    ('canceled', 'Canceled'),
-    ('rejected', 'Rejected')
-)
-
-def generate_random(length=SECRET_SIZE):
-    return User.objects.make_random_password(length=length)
-
-class Nonce(models.Model):
-    token_key = models.CharField(max_length=KEY_SIZE)
-    consumer_key = models.CharField(max_length=KEY_SIZE)
-    key = models.CharField(max_length=255)
-    
-    def __unicode__(self):
-        return u"Nonce %s for %s" % (self.key, self.consumer_key)
-
-admin.site.register(Nonce)
-
-class Consumer(models.Model):
-    name = models.CharField(max_length=255)
-    description = models.TextField()
-
-    key = models.CharField(max_length=KEY_SIZE)
-    secret = models.CharField(max_length=SECRET_SIZE)
-
-    status = models.CharField(max_length=16, choices=CONSUMER_STATES, default='pending')
-    user = models.ForeignKey(User, null=True, blank=True, related_name='consumers')
-
-    objects = ConsumerManager()
-        
-    def __unicode__(self):
-        return u"Consumer %s with key %s" % (self.name, self.key)
-
-    def generate_random_codes(self):
-        """
-        Used to generate random key/secret pairings. Use this after you've
-        added the other data in place of save(). 
-
-        c = Consumer()
-        c.name = "My consumer" 
-        c.description = "An app that makes ponies from the API."
-        c.user = some_user_object
-        c.generate_random_codes()
-        """
-        key = User.objects.make_random_password(length=KEY_SIZE)
-        secret = generate_random(SECRET_SIZE)
-
-        while Consumer.objects.filter(key__exact=key, secret__exact=secret).count():
-            secret = generate_random(SECRET_SIZE)
-
-        self.key = key
-        self.secret = secret
-        self.save()
-
-admin.site.register(Consumer)
-
-class Token(models.Model):
-    REQUEST = 1
-    ACCESS = 2
-    TOKEN_TYPES = ((REQUEST, u'Request'), (ACCESS, u'Access'))
-    
-    key = models.CharField(max_length=KEY_SIZE)
-    secret = models.CharField(max_length=SECRET_SIZE)
-    verifier = models.CharField(max_length=VERIFIER_SIZE)
-    token_type = models.IntegerField(choices=TOKEN_TYPES)
-    timestamp = models.IntegerField(default=long(time.time()))
-    is_approved = models.BooleanField(default=False)
-    
-    user = models.ForeignKey(User, null=True, blank=True, related_name='tokens')
-    consumer = models.ForeignKey(Consumer)
-    
-    callback = models.CharField(max_length=255, null=True, blank=True)
-    callback_confirmed = models.BooleanField(default=False)
-    
-    objects = TokenManager()
-    
-    def __unicode__(self):
-        return u"%s Token %s for %s" % (self.get_token_type_display(), self.key, self.consumer)
-
-    def to_string(self, only_key=False):
-        token_dict = {
-            'oauth_token': self.key, 
-            'oauth_token_secret': self.secret,
-            'oauth_callback_confirmed': 'true',
-        }
-
-        if self.verifier:
-            token_dict.update({ 'oauth_verifier': self.verifier })
-
-        if only_key:
-            del token_dict['oauth_token_secret']
-
-        return urllib.urlencode(token_dict)
-
-    def generate_random_codes(self):
-        key = User.objects.make_random_password(length=KEY_SIZE)
-        secret = generate_random(SECRET_SIZE)
-
-        while Token.objects.filter(key__exact=key, secret__exact=secret).count():
-            secret = generate_random(SECRET_SIZE)
-
-        self.key = key
-        self.secret = secret
-        self.save()
-        
-    # -- OAuth 1.0a stuff
-
-    def get_callback_url(self):
-        if self.callback and self.verifier:
-            # Append the oauth_verifier.
-            parts = urlparse.urlparse(self.callback)
-            scheme, netloc, path, params, query, fragment = parts[:6]
-            if query:
-                query = '%s&oauth_verifier=%s' % (query, self.verifier)
-            else:
-                query = 'oauth_verifier=%s' % self.verifier
-            return urlparse.urlunparse((scheme, netloc, path, params,
-                query, fragment))
-        return self.callback
-    
-    def set_callback(self, callback):
-        if callback != "oob": # out of band, says "we can't do this!"
-            self.callback = callback
-            self.callback_confirmed = True
-            self.save()
-        
-admin.site.register(Token)
-
-# Attach our signals
-post_save.connect(consumer_post_save, sender=Consumer)
-post_delete.connect(consumer_post_delete, sender=Consumer)

libs/piston/oauth.py

-"""
-The MIT License
-
-Copyright (c) 2007 Leah Culver
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-"""
-
-import cgi
-import urllib
-import time
-import random
-import urlparse
-import hmac
-import binascii
-
-
-VERSION = '1.0' # Hi Blaine!
-HTTP_METHOD = 'GET'
-SIGNATURE_METHOD = 'PLAINTEXT'
-
-
-class OAuthError(RuntimeError):
-    """Generic exception class."""
-    def __init__(self, message='OAuth error occured.'):
-        self.message = message
-
-def build_authenticate_header(realm=''):
-    """Optional WWW-Authenticate header (401 error)"""
-    return {'WWW-Authenticate': 'OAuth realm="%s"' % realm}
-
-def escape(s):
-    """Escape a URL including any /."""
-    return urllib.quote(s, safe='~')
-
-def _utf8_str(s):
-    """Convert unicode to utf-8."""
-    if isinstance(s, unicode):
-        return s.encode("utf-8")
-    else:
-        return str(s)
-
-def generate_timestamp():
-    """Get seconds since epoch (UTC)."""
-    return int(time.time())
-
-def generate_nonce(length=8):
-    """Generate pseudorandom number."""
-    return ''.join([str(random.randint(0, 9)) for i in range(length)])
-
-def generate_verifier(length=8):
-    """Generate pseudorandom number."""
-    return ''.join([str(random.randint(0, 9)) for i in range(length)])
-
-
-class OAuthConsumer(object):
-    """Consumer of OAuth authentication.
-
-    OAuthConsumer is a data type that represents the identity of the Consumer
-    via its shared secret with the Service Provider.
-
-    """
-    key = None
-    secret = None
-
-    def __init__(self, key, secret):
-        self.key = key
-        self.secret = secret
-
-
-class OAuthToken(object):
-    """OAuthToken is a data type that represents an End User via either an access
-    or request token.
-    
-    key -- the token
-    secret -- the token secret
-
-    """
-    key = None
-    secret = None
-    callback = None
-    callback_confirmed = None
-    verifier = None
-
-    def __init__(self, key, secret):
-        self.key = key
-        self.secret = secret
-
-    def set_callback(self, callback):
-        self.callback = callback
-        self.callback_confirmed = 'true'
-
-    def set_verifier(self, verifier=None):
-        if verifier is not None:
-            self.verifier = verifier
-        else:
-            self.verifier = generate_verifier()
-
-    def get_callback_url(self):
-        if self.callback and self.verifier:
-            # Append the oauth_verifier.
-            parts = urlparse.urlparse(self.callback)
-            scheme, netloc, path, params, query, fragment = parts[:6]
-            if query:
-                query = '%s&oauth_verifier=%s' % (query, self.verifier)
-            else:
-                query = 'oauth_verifier=%s' % self.verifier
-            return urlparse.urlunparse((scheme, netloc, path, params,
-                query, fragment))
-        return self.callback
-
-    def to_string(self):
-        data = {
-            'oauth_token': self.key,
-            'oauth_token_secret': self.secret,
-        }
-        if self.callback_confirmed is not None:
-            data['oauth_callback_confirmed'] = self.callback_confirmed
-        return urllib.urlencode(data)
- 
-    def from_string(s):
-        """ Returns a token from something like:
-        oauth_token_secret=xxx&oauth_token=xxx
-        """
-        params = cgi.parse_qs(s, keep_blank_values=False)
-        key = params['oauth_token'][0]
-        secret = params['oauth_token_secret'][0]
-        token = OAuthToken(key, secret)
-        try:
-            token.callback_confirmed = params['oauth_callback_confirmed'][0]
-        except KeyError:
-            pass # 1.0, no callback confirmed.
-        return token
-    from_string = staticmethod(from_string)
-
-    def __str__(self):
-        return self.to_string()
-
-
-class OAuthRequest(object):
-    """OAuthRequest represents the request and can be serialized.
-
-    OAuth parameters:
-        - oauth_consumer_key 
-        - oauth_token
-        - oauth_signature_method
-        - oauth_signature 
-        - oauth_timestamp 
-        - oauth_nonce
-        - oauth_version
-        - oauth_verifier
-        ... any additional parameters, as defined by the Service Provider.
-    """
-    parameters = None # OAuth parameters.
-    http_method = HTTP_METHOD
-    http_url = None
-    version = VERSION
-
-    def __init__(self, http_method=HTTP_METHOD, http_url=None, parameters=None):
-        self.http_method = http_method
-        self.http_url = http_url
-        self.parameters = parameters or {}
-
-    def set_parameter(self, parameter, value):
-        self.parameters[parameter] = value
-
-    def get_parameter(self, parameter):
-        try:
-            return self.parameters[parameter]
-        except:
-            raise OAuthError('Parameter not found: %s' % parameter)
-
-    def _get_timestamp_nonce(self):
-        return self.get_parameter('oauth_timestamp'), self.get_parameter(
-            'oauth_nonce')
-
-    def get_nonoauth_parameters(self):
-        """Get any non-OAuth parameters."""
-        parameters = {}
-        for k, v in self.parameters.iteritems():
-            # Ignore oauth parameters.
-            if k.find('oauth_') < 0:
-                parameters[k] = v
-        return parameters
-
-    def to_header(self, realm=''):
-        """Serialize as a header for an HTTPAuth request."""
-        auth_header = 'OAuth realm="%s"' % realm
-        # Add the oauth parameters.
-        if self.parameters:
-            for k, v in self.parameters.iteritems():
-                if k[:6] == 'oauth_':
-                    auth_header += ', %s="%s"' % (k, escape(str(v)))
-        return {'Authorization': auth_header}
-
-    def to_postdata(self):
-        """Serialize as post data for a POST request."""
-        return '&'.join(['%s=%s' % (escape(str(k)), escape(str(v))) \
-            for k, v in self.parameters.iteritems()])
-
-    def to_url(self):
-        """Serialize as a URL for a GET request."""
-        return '%s?%s' % (self.get_normalized_http_url(), self.to_postdata())
-
-    def get_normalized_parameters(self):
-        """Return a string that contains the parameters that must be signed."""
-        params = self.parameters
-        try:
-            # Exclude the signature if it exists.
-            del params['oauth_signature']
-        except:
-            pass
-        # Escape key values before sorting.
-        key_values = [(escape(_utf8_str(k)), escape(_utf8_str(v))) \
-            for k,v in params.items()]
-        # Sort lexicographically, first after key, then after value.
-        key_values.sort()
-        # Combine key value pairs into a string.
-        return '&'.join(['%s=%s' % (k, v) for k, v in key_values])
-
-    def get_normalized_http_method(self):
-        """Uppercases the http method."""
-        return self.http_method.upper()
-
-    def get_normalized_http_url(self):
-        """Parses the URL and rebuilds it to be scheme://host/path."""
-        parts = urlparse.urlparse(self.http_url)
-        scheme, netloc, path = parts[:3]
-        # Exclude default port numbers.
-        if scheme == 'http' and netloc[-3:] == ':80':
-            netloc = netloc[:-3]
-        elif scheme == 'https' and netloc[-4:] == ':443':
-            netloc = netloc[:-4]
-        return '%s://%s%s' % (scheme, netloc, path)
-
-    def sign_request(self, signature_method, consumer, token):
-        """Set the signature parameter to the result of build_signature."""
-        # Set the signature method.
-        self.set_parameter('oauth_signature_method',
-            signature_method.get_name())
-        # Set the signature.
-        self.set_parameter('oauth_signature',
-            self.build_signature(signature_method, consumer, token))
-
-    def build_signature(self, signature_method, consumer, token):
-        """Calls the build signature method within the signature method."""
-        return signature_method.build_signature(self, consumer, token)
-
-    def from_request(http_method, http_url, headers=None, parameters=None,
-            query_string=None):
-        """Combines multiple parameter sources."""
-        if parameters is None:
-            parameters = {}
-
-        # Headers
-        if headers and 'Authorization' in headers:
-            auth_header = headers['Authorization']
-            # Check that the authorization header is OAuth.
-            if auth_header[:6] == 'OAuth ':
-                auth_header = auth_header[6:]
-                try:
-                    # Get the parameters from the header.
-                    header_params = OAuthRequest._split_header(auth_header)
-                    parameters.update(header_params)
-                except:
-                    raise OAuthError('Unable to parse OAuth parameters from '
-                        'Authorization header.')
-
-        # GET or POST query string.
-        if query_string:
-            query_params = OAuthRequest._split_url_string(query_string)
-            parameters.update(query_params)
-
-        # URL parameters.
-        param_str = urlparse.urlparse(http_url)[4] # query
-        url_params = OAuthRequest._split_url_string(param_str)
-        parameters.update(url_params)
-
-        if parameters:
-            return OAuthRequest(http_method, http_url, parameters)
-
-        return None
-    from_request = staticmethod(from_request)
-
-    def from_consumer_and_token(oauth_consumer, token=None,
-            callback=None, verifier=None, http_method=HTTP_METHOD,
-            http_url=None, parameters=None):
-        if not parameters:
-            parameters = {}
-
-        defaults = {
-            'oauth_consumer_key': oauth_consumer.key,
-            'oauth_timestamp': generate_timestamp(),
-            'oauth_nonce': generate_nonce(),
-            'oauth_version': OAuthRequest.version,
-        }
-
-        defaults.update(parameters)
-        parameters = defaults
-
-        if token:
-            parameters['oauth_token'] = token.key
-            parameters['oauth_callback'] = token.callback
-            # 1.0a support for verifier.
-            parameters['oauth_verifier'] = verifier
-        elif callback:
-            # 1.0a support for callback in the request token request.
-            parameters['oauth_callback'] = callback
-
-        return OAuthRequest(http_method, http_url, parameters)
-    from_consumer_and_token = staticmethod(from_consumer_and_token)
-
-    def from_token_and_callback(token, callback=None, http_method=HTTP_METHOD,
-            http_url=None, parameters=None):
-        if not parameters:
-            parameters = {}
-
-        parameters['oauth_token'] = token.key
-
-        if callback:
-            parameters['oauth_callback'] = callback
-
-        return OAuthRequest(http_method, http_url, parameters)
-    from_token_and_callback = staticmethod(from_token_and_callback)
-
-    def _split_header(header):
-        """Turn Authorization: header into parameters."""
-        params = {}
-        parts = header.split(',')
-        for param in parts:
-            # Ignore realm parameter.
-            if param.find('realm') > -1:
-                continue
-            # Remove whitespace.
-            param = param.strip()
-            # Split key-value.