'Sign a request
Signs an HTTP request with the specified parts.
Returns a 3-tuple of the signed request\'s URI, headers, and body.
Note that http_method is not returned as it is unaffected by the OAuth
signing process. Also worth noting is that duplicate parameters
will be included in the signature, regardless of where they are
specified (query, body).
The body argument may be a dict, a list of 2-tuples, or a formencoded
string. The Content-Type header must be \'application/x-www-form-urlencoded\'
if it is present.
If the body argument is not one of the above, it will be returned
verbatim as it is unaffected by the OAuth signing process. Attempting to
sign a request with non-formencoded data using the OAuth body signature
type is invalid and will raise an exception.
If the body does contain parameters, it will be returned as a properly-
formatted formencoded string.
Body may not be included if the http_method is either GET or HEAD as
this changes the semantic meaning of the request.
All string data MUST be unicode or be encoded with the same encoding
scheme supplied to the Client constructor, default utf-8. This includes
strings inside body dicts, for example.'

def sign(self, uri, http_method=u'GET', body=None, headers=None, realm=None):

    request = Request(uri, http_method, body, headers, encoding=self.encoding)
    content_type = request.headers.get(u'Content-Type', None)
    multipart = (content_type and content_type.startswith(u'multipart/'))
    should_have_params = (content_type == CONTENT_TYPE_FORM_URLENCODED)
    has_params = (request.decoded_body is not None)
    if (multipart and has_params):
        raise ValueError(u'Headers    indicate    a    multipart    body    but    body    contains    parameters.')
    elif (should_have_params and (not has_params)):
        raise ValueError(u'Headers    indicate    a    formencoded    body    but    body    was    not    decodable.')
    elif ((not should_have_params) and has_params):
        raise ValueError(u'Body    contains    parameters    but    Content-Type    header    was    {0}    instead    of    {1}'.format((content_type or u'not    set'), CONTENT_TYPE_FORM_URLENCODED))
    elif ((self.signature_type == SIGNATURE_TYPE_BODY) and (not (should_have_params and has_params and (not multipart)))):
        raise ValueError(u'Body    signatures    may    only    be    used    with    form-urlencoded    content')
    elif ((http_method.upper() in (u'GET', u'HEAD')) and has_params):
        raise ValueError(u'GET/HEAD    requests    should    not    include    body.')
    request.oauth_params = self.get_oauth_params(request)
    request.oauth_params.append((u'oauth_signature', self.get_oauth_signature(request)))
    (uri, headers, body) = self._render(request, formencode=True, realm=(realm or self.realm))
    if self.decoding:
        log.debug(u'Encoding    URI,    headers    and    body    to    %s.', self.decoding)
        uri = uri.encode(self.decoding)
        body = (body.encode(self.decoding) if body else body)
        new_headers = {}
        for (k, v) in headers.items():
            new_headers[k.encode(self.decoding)] = v.encode(self.decoding)
        headers = new_headers
    return (uri, headers, body)
