def jsonrpc_method(name,
                   authenticated=False,
                   authentication_arguments=['username', 'password'],
                   safe=False,
                   validate=False,
                   site=default_site):
    """
    Wraps a function turns it into a json-rpc method. Adds several attributes
    to the function specific to the JSON-RPC machinery and adds it to the default
    jsonrpc_site if one isn't provided. You must import the module containing
    these functions in your urls.py.

        name

            The name of your method. IE: `namespace.methodName` The method name
            can include type information, like `ns.method(String, Array) -> Nil`.

        authenticated=False

            Adds `username` and `password` arguments to the beginning of your
            method if the user hasn't already been authenticated. These will
            be used to authenticate the user against `django.contrib.authenticate`
            If you use HTTP auth or other authentication middleware, `username`
            and `password` will not be added, and this method will only check
            against `request.user.is_authenticated`.

            You may pass a callable to replace `django.contrib.auth.authenticate`
            as the authentication method. It must return either a User or `None`
            and take the keyword arguments `username` and `password`.

        safe=False

            Designates whether or not your method may be accessed by HTTP GET.
            By default this is turned off.

        validate=False

            Validates the arguments passed to your method based on type
            information provided in the signature. Supply type information by
            including types in your method declaration. Like so:

            @jsonrpc_method('myapp.specialSauce(Array, String)', validate=True)
            def special_sauce(self, ingredients, instructions):
              return SpecialSauce(ingredients, instructions)

            Calls to `myapp.specialSauce` will now check each arguments type
            before calling `special_sauce`, throwing an `InvalidParamsError`
            when it encounters a discrepancy. This can significantly reduce the
            amount of code required to write JSON-RPC services.

        site=default_site

            Defines which site the jsonrpc method will be added to. Can be any
            object that provides a `register(name, func)` method.

    """

    def decorator(func):
        arg_names = getargspec(func)[0][1:]
        X = {'name': name, 'arg_names': arg_names}
        if authenticated:
            if authenticated is True or six.callable(authenticated):
                # TODO: this is an assumption
                X['arg_names'] = authentication_arguments + X['arg_names']
                X['name'] = _inject_args(X['name'], ('String', 'String'))
                from django.contrib.auth import authenticate as _authenticate
                from django.contrib.auth.models import User
            else:
                authenticate = authenticated

            @six.wraps(func)
            def _func(request, *args, **kwargs):
                user = getattr(request, 'user', None)
                is_authenticated = getattr(user, 'is_authenticated',
                                           lambda: False)
                if ((user is not None and six.callable(is_authenticated) and
                     not is_authenticated()) or user is None):
                    user = None
                    try:
                        creds = args[:len(authentication_arguments)]
                        if len(creds) == 0:
                            raise IndexError
                        # Django's authenticate() method takes arguments as dict
                        user = _authenticate(username=creds[0],
                                             password=creds[1], *creds[2:])
                        if user is not None:
                            args = args[len(authentication_arguments):]
                    except IndexError:
                        auth_kwargs = {}
                        try:
                            for auth_kwarg in authentication_arguments:
                                auth_kwargs[auth_kwarg] = kwargs[auth_kwarg]
                        except KeyError:
                            raise InvalidParamsError(
                                'Authenticated methods require at least '
                                '[%(arguments)s] or {%(arguments)s} arguments' %
                                {'arguments': ', '.join(authentication_arguments)})

                        user = _authenticate(**auth_kwargs)
                        if user is not None:
                            for auth_kwarg in authentication_arguments:
                                kwargs.pop(auth_kwarg)
                    if user is None:
                        raise InvalidCredentialsError
                    request.user = user
                return func(request, *args, **kwargs)
        else:
            _func = func

        @six.wraps(_func)
        def exc_printer(*a, **kw):
            try:
                return _func(*a, **kw)
            except Exception as e:
                try:
                    print('JSONRPC SERVICE EXCEPTION')
                    import traceback
                    traceback.print_exc()
                except:
                    pass
                six.reraise(*sys.exc_info())

        ret_func = exc_printer

        method, arg_types, return_type = \
      _parse_sig(X['name'], X['arg_names'], validate)
        ret_func.json_args = X['arg_names']
        ret_func.json_arg_types = arg_types
        ret_func.json_return_type = return_type
        ret_func.json_method = method
        ret_func.json_safe = safe
        ret_func.json_sig = X['name']
        ret_func.json_validate = validate
        site.register(method, ret_func)
        return ret_func

    return decorator
def jsonrpc_method ( name , authenticated = False , authentication_arguments = [ 'username' , 'password' ] , safe = False , validate = False , site = default_site ) : def decorator ( func ) : arg_names = getargspec ( func ) [ 0 ] [ 1 : ] X = { 'name' : name , 'arg_names' : arg_names } if authenticated : if authenticated is True or six . callable ( authenticated ) : X [ 'arg_names' ] = authentication_arguments + X [ 'arg_names' ] X [ 'name' ] = _inject_args ( X [ 'name' ] , ( 'String' , 'String' ) ) from django . contrib . auth import authenticate as _authenticate from django . contrib . auth . models import User else : authenticate = authenticated @ six . wraps ( func ) def _func ( request , * args , ** kwargs ) : user = getattr ( request , 'user' , None ) is_authenticated = getattr ( user , 'is_authenticated' , lambda : False ) if ( ( user is not None and six . callable ( is_authenticated ) and not is_authenticated ( ) ) or user is None ) : user = None try : creds = args [ : len ( authentication_arguments ) ] if len ( creds ) == 0 : raise IndexError user = _authenticate ( username = creds [ 0 ] , password = creds [ 1 ] , * creds [ 2 : ] ) if user is not None : args = args [ len ( authentication_arguments ) : ] except IndexError : auth_kwargs = { } try : for auth_kwarg in authentication_arguments : auth_kwargs [ auth_kwarg ] = kwargs [ auth_kwarg ] except KeyError : raise InvalidParamsError ( 'Authenticated methods require at least ' '[%(arguments)s] or {%(arguments)s} arguments' % { 'arguments' : ', ' . join ( authentication_arguments ) } ) user = _authenticate ( ** auth_kwargs ) if user is not None : for auth_kwarg in authentication_arguments : kwargs . pop ( auth_kwarg ) if user is None : raise InvalidCredentialsError request . user = user return func ( request , * args , ** kwargs ) else : _func = func @ six . wraps ( _func ) def exc_printer ( * a , ** kw ) : try : return _func ( * a , ** kw ) except Exception as e : try : print ( 'JSONRPC SERVICE EXCEPTION' ) import traceback traceback . print_exc ( ) except : pass six . reraise ( * sys . exc_info ( ) ) ret_func = exc_printer method , arg_types , return_type = _parse_sig ( X [ 'name' ] , X [ 'arg_names' ] , validate ) ret_func . json_args = X [ 'arg_names' ] ret_func . json_arg_types = arg_types ret_func . json_return_type = return_type ret_func . json_method = method ret_func . json_safe = safe ret_func . json_sig = X [ 'name' ] ret_func . json_validate = validate site . register ( method , ret_func ) return ret_func return decorator
Wraps a function turns it into a json-rpc method. Adds several attributes
    to the function specific to the JSON-RPC machinery and adds it to the default
    jsonrpc_site if one isn't provided. You must import the module containing
    these functions in your urls.py.

        name

            The name of your method. IE: `namespace.methodName` The method name
            can include type information, like `ns.method(String, Array) -> Nil`.

        authenticated=False

            Adds `username` and `password` arguments to the beginning of your
            method if the user hasn't already been authenticated. These will
            be used to authenticate the user against `django.contrib.authenticate`
            If you use HTTP auth or other authentication middleware, `username`
            and `password` will not be added, and this method will only check
            against `request.user.is_authenticated`.

            You may pass a callable to replace `django.contrib.auth.authenticate`
            as the authentication method. It must return either a User or `None`
            and take the keyword arguments `username` and `password`.

        safe=False

            Designates whether or not your method may be accessed by HTTP GET.
            By default this is turned off.

        validate=False

            Validates the arguments passed to your method based on type
            information provided in the signature. Supply type information by
            including types in your method declaration. Like so:

            @jsonrpc_method('myapp.specialSauce(Array, String)', validate=True)
            def special_sauce(self, ingredients, instructions):
              return SpecialSauce(ingredients, instructions)

            Calls to `myapp.specialSauce` will now check each arguments type
            before calling `special_sauce`, throwing an `InvalidParamsError`
            when it encounters a discrepancy. This can significantly reduce the
            amount of code required to write JSON-RPC services.

        site=default_site

            Defines which site the jsonrpc method will be added to. Can be any
            object that provides a `register(name, func)` method.