Make request to endpoint with OAuth.
        Returns dictionary with response data.

        :param endpoint: endpoint path, or a fully qualified URL if raw=True.
        :param method: GET (default), POST or DELETE.
        :param data: data to send in the request body.
        :param raw: use endpoint as entered without trying to modify it.
        :param params: dictionary of parameters to send in the query string.
        :param retries: number of times to retry if a request fails.
        :param client: OAuth client data, if False do request without OAuth.
        :param headers: dictionary of HTTP headers.
        :param timeout: the timeout for a request, in seconds.

        Example:
            >>> pump.request('https://e14n.com/api/user/evan/profile', raw=True)
            {u'displayName': u'Evan Prodromou',
             u'favorites': {u'totalItems': 7227,
              u'url': u'https://e14n.com/api/user/evan/favorites'},
             u'id': u'acct:evan@e14n.com',
             u'image': {u'height': 96,
              u'url': u'https://e14n.com/uploads/evan/2014/9/24/knyf1g_thumb.jpg',
              u'width': 96},
             u'liked': False,
             u'location': {u'displayName': u'Montreal, Quebec, Canada',
              u'objectType': u'place'},
             u'objectType': u'person',
             u'preferredUsername': u'evan',
             u'published': u'2013-02-20T15:34:52Z',
             u'summary': u'I wanna make it with you. http://payb.tc/evanp',
             u'updated': u'2014-09-24T02:38:32Z',
             u'url': u'https://e14n.com/evan'}

def request(self, endpoint, method="GET", data="",
                raw=False, params=None, retries=None, client=None,
                headers=None, timeout=None, **kwargs):
        """ Make request to endpoint with OAuth.
        Returns dictionary with response data.

        :param endpoint: endpoint path, or a fully qualified URL if raw=True.
        :param method: GET (default), POST or DELETE.
        :param data: data to send in the request body.
        :param raw: use endpoint as entered without trying to modify it.
        :param params: dictionary of parameters to send in the query string.
        :param retries: number of times to retry if a request fails.
        :param client: OAuth client data, if False do request without OAuth.
        :param headers: dictionary of HTTP headers.
        :param timeout: the timeout for a request, in seconds.

        Example:
            >>> pump.request('https://e14n.com/api/user/evan/profile', raw=True)
            {u'displayName': u'Evan Prodromou',
             u'favorites': {u'totalItems': 7227,
              u'url': u'https://e14n.com/api/user/evan/favorites'},
             u'id': u'acct:evan@e14n.com',
             u'image': {u'height': 96,
              u'url': u'https://e14n.com/uploads/evan/2014/9/24/knyf1g_thumb.jpg',
              u'width': 96},
             u'liked': False,
             u'location': {u'displayName': u'Montreal, Quebec, Canada',
              u'objectType': u'place'},
             u'objectType': u'person',
             u'preferredUsername': u'evan',
             u'published': u'2013-02-20T15:34:52Z',
             u'summary': u'I wanna make it with you. http://payb.tc/evanp',
             u'updated': u'2014-09-24T02:38:32Z',
             u'url': u'https://e14n.com/evan'}
        """

        retries = self.retries if retries is None else retries
        timeout = self.timeout if timeout is None else timeout

        # check client has been setup
        if client is None:
            client = self.setup_oauth_client(endpoint)
            c = client.client
            fnc = OAuth1Session(c.client_key,
                                client_secret=c.client_secret,
                                resource_owner_key=c.resource_owner_key,
                                resource_owner_secret=c.resource_owner_secret
                               )
        elif client is False:
            fnc = requests

        params = {} if params is None else params

        if data and isinstance(data, dict):
            data = json.dumps(data)

        if not raw:
            url = self._build_url(endpoint)
        else:
            url = endpoint

        headers = headers or {"Content-Type": "application/json"}
        request = {
            "headers": headers,
            "params": params,
            "timeout": timeout,
        }
        request.update(kwargs)

        if method == "POST":
            fnc = fnc.post
            request.update({"data": data})
        elif method == "PUT":
            fnc = fnc.put
            request.update({"data": data})
        elif method == "GET":
            fnc = fnc.get
        elif method == "DELETE":
            fnc = fnc.delete

        for attempt in range(1 + retries):
            response = self._requester(
                fnc=fnc,
                endpoint=endpoint,
                raw=raw,
                **request
            )

            if response.status_code == 200:
                # huray!
                return response.json()

            if response.status_code == 400:
                # can't do much
                try:
                    try:
                        data = response.json()
                        error = data["error"]
                    except ValueError:
                        error = response.content

                    if not error:
                        raise IndexError  # yesss i know.
                except IndexError:
                    error = "400 - Bad request."
                raise PyPumpException(error)

            if response.ok:
                return response

        error = "Request Failed to {url} (response: {data} | status: {status})"
        error = error.format(
            url=url,
            data=response.content,
            status=response.status_code
        )

        raise PyPumpException(error)