def on_status(self, status):
   search_params = {}
   for word in status.text.split(" "):
     results = [k for k, v in dict.iteritems() if word.capitalize() in v]
     if results:
       search_params.setdefault(results[0], []).append(word.capitalize())
   if search_params:
     data = urlencode({"q": search_params, "limit": 5, "order":"rolling_rank DESC"})
     response = requests.get(url + "?" + data)
     if response.ok:
       if response.json():
         tweet_positive_result(response, status)
       else:
         tweet_random_result(status)
     else:
       response.raise_for_status()
   else:
     search_params['search'] = [status.text.replace("#marmomood", "")]
     data = urlencode({"q": search_params, "limit": 1, "order":"rolling_rank DESC"})
     response = requests.get(url + "?" + data)
     if response.ok:
       if response.json():
         tweet_positive_result(response, status)
       else:
         tweet_random_result(status)
     else:
       response.raise_for_status()
Example #2
0
 def search_articles(self, phrase, **kwargs):
     """Search article matching phrase."""
     for key in kwargs:
         if key not in ['status', '_fields', 'limit']:
             raise InvalidArg(key)
     return self.__call(self.knowledgeowl.suggest, 'GET',
                        data=urlencode({'phrase': phrase}),
                        params=urlencode(kwargs)).json()
    def call(self, method, params1=None, params2=None, params3=None, params4=None):
        """Call Bitrix24 API method
        :param method: Method name
        :param params1: Method parameters 1
        :param params2: Method parameters 2. Needed for methods with determinate consequence of parameters
        :param params3: Method parameters 3. Needed for methods with determinate consequence of parameters
        :param params4: Method parameters 4. Needed for methods with determinate consequence of parameters
        :return: Call result
        """
        if method == '' or not isinstance(method, str):
            raise Exception('Empty Method')

        if method == 'batch' and 'prepared' not in params1:
            params1['cmd'] = self.prepare_batch(params1['cmd'])
            params1['prepared'] = True

        encoded_parameters = ''

        # print params1
        for i in [params1, params2, params3, params4]:
            if i is not None:
                if 'cmd' in i:
                    i = dict(i)
                    encoded_parameters += self.encode_cmd(i['cmd']) + '&' + urlencode({'halt': i['halt']}) + '&'
                elif 'filter' in i:
                    # i = dict(i)
                    encoded_parameters += urlencode(i)
                else:
                    encoded_parameters += urlencode(i) + '&'

        r = {}
        try:
            # request url
            url = self.get_url(method)
            # Make API request
            r = post(url, data=encoded_parameters, timeout=self.timeout)
            # Decode response
            result = loads(r.text)
        except ValueError:
            result = dict(error='Error on decode api response [%s]' % r.text)
        except exceptions.ReadTimeout:
            result = dict(error='Timeout waiting expired [%s sec]' % str(self.timeout))
        except exceptions.ConnectionError:
            result = dict(error='Max retries exceeded [' + str(adapters.DEFAULT_RETRIES) + ']')
        if 'error' in result and result['error'] in ('NO_AUTH_FOUND', 'expired_token'):
            result = self.refresh_tokens()
            if result is not True:
                return result
            # Repeat API request after renew token
            result = self.call(method, params1, params2, params3, params4)
        elif 'error' in result and result['error'] in ('QUERY_LIMIT_EXCEEDED',):
            # Suspend call on two second, wait for expired limitation time by Bitrix24 API
            print('SLEEP =)')
            sleep(2)
            return self.call(method, params1, params2, params3, params4)
        return result
Example #4
0
    def send(self):
        """
        Send the request to the remote url.
        :return:
        """

        client = self.client
        get_params = client.params_get
        request_url = client.url.rstrip('/')

        if get_params:
            sorted_get_params = OrderedDict(sorted(get_params.items()))
            query_string = urlencode(sorted_get_params)

            if query_string:
                request_url += '?' + query_string

        self._sign(request_url)

        if client.is_put_method() or client.is_delete_method():
            client.headers['X-HTTP-Method-Override'] = client.method.upper()

        response = self._make_request()

        return response
def bitrix_request(method, params, rec=True, post=True):
    url = _main_url.replace('METHOD', method)
    # url = url.replace('AUTH', _token['access_token'])
    params['auth'] = _token['access_token']

    if post:
        req = requests.post(url,
                            data=json.dumps(params, default=json_serial),
                            headers=headers)
    else:
        req = requests.get(url, params=urlencode(params))

    if req.status_code == 401:
        if rec:
            update_token()
            time.sleep(10)
            return bitrix_request(method, params, rec=False)
        else:
            raise Exception('401 error while requesting {}'.format(url))
    elif req.status_code == 400:
        logging.error('Wrong data, {}'.format(req.content))
    elif req.status_code != 200:
        time.sleep(10)
        if rec:
            return bitrix_request(method, params, rec=False)
        else:
            logging.info('{} error while requesting a {}'.format(
                req.status_code, url))
            logging.info('Second try was failed, possible data loss')

    # return json.loads(req.content.decode('utf-8'))
    return req.json()
Example #6
0
 def get_article(self, article_id, **kwargs):
     """Retrieve article and it's current version html."""
     for key in kwargs:
         if key not in ['replaceSnippets', '_fields']:
             raise InvalidArg(key)
     return self.__call(self.knowledgeowl.article(article_id), 'GET',
                        data=json.dumps({'_fields': 'current_version'}),
                        params=urlencode(kwargs))
Example #7
0
    def call(self,
             method,
             params1=None,
             params2=None,
             params3=None,
             params4=None):
        """Call Bitrix24 API method
        :param method: Method name
        :param params1: Method parameters 1
        :param params2: Method parameters 2. Needed for methods with determinate consequence of parameters
        :param params3: Method parameters 3. Needed for methods with determinate consequence of parameters
        :param params4: Method parameters 4. Needed for methods with determinate consequence of parameters
        :return: Call result
        """
        if method == '' or not isinstance(method, str):
            raise Exception('Empty Method')

        encoded_parameters = ''

        for i in [
                params1, params2, params3, params4, {
                    'auth': self.auth_token
                }
        ]:
            if i is not None:
                encoded_parameters += urlencode(i) + '&'

        r = {}

        try:
            # request url
            url = self.api_url % (self.domain, self.high_level_domain, method)
            # Make API request
            r = post(url, params=encoded_parameters, timeout=self.timeout)
            # Decode response
            result = loads(r.text)
        except ValueError:
            result = dict(error='Error on decode api response [' + r.text +
                          ']')
        except exceptions.ReadTimeout:
            result = dict(error='Timeout waiting expired [' +
                          str(self.timeout) + ' sec]')
        except exceptions.ConnectionError:
            result = dict(error='Max retries exceeded [' +
                          str(adapters.DEFAULT_RETRIES) + ']')
        if 'error' in result and result['error'] in ('NO_AUTH_FOUND',
                                                     'expired_token'):
            result = self.refresh_tokens()
            if result is not True:
                return result
            # Repeat API request after renew token
            result = self.call(method, params1, params2, params3, params4)
        elif 'error' in result and result['error'] in 'QUERY_LIMIT_EXCEEDED':
            # Suspend call on two second, wait for expired limitation time by Bitrix24 API
            sleep(2)
            return self.call(method, params1, params2, params3, params4)

        return result
Example #8
0
    def list_articles(self, **kwargs):
        """List all articles."""
        m_keys = list(ARTICLE_KEYS)
        m_keys.extend(['sort', 'limit'])
        for key in kwargs:
            if key not in m_keys:
                raise InvalidArg(key)

        return self.__call(self.knowledgeowl.article, 'GET', params=urlencode(kwargs))
Example #9
0
    def encode_cmd(cmd):
        """Resort batch cmd by request keys and encode it
        :param cmd: dict List methods for batch request with request ids
        :return: str
        """
        cmd_encoded = ''

        for i in sorted(cmd.keys()):
            cmd_encoded += urlencode({'cmd': {i: cmd[i]}}) + '&'

        return cmd_encoded
Example #10
0
def tweet_random_result(status):
  data = urlencode({"limit": 10, "order":"rolling_rank DESC"})
  response = requests.get(url + "?" + data)
  if response.ok:
    if response.json():
      random_track = random.choice(response.tracks())
      message = '''@{0} I couldn't find that. Why don't you check out "{1}," it's one of our hottest songs: {2}'''.format(status.user.screen_name, random_track.title, shorten_url(random_track.url))
      api.update_status(shorten_message(message, random_track), in_reply_to_status_id = status.id)
    else:
      message = "@{0} your search was so specific, I couldn't find anything. Please try again.".format(status.user.screen_name)
      api.update_status(message, in_reply_to_status_id = status.id)
  else:
    response.raise_for_status()
Example #11
0
 def on_status(self, status):
     search_params = {}
     for word in status.text.split(" "):
         results = [
             k for k, v in dict.iteritems() if word.capitalize() in v
         ]
         if results:
             search_params.setdefault(results[0],
                                      []).append(word.capitalize())
     if search_params:
         data = urlencode({
             "q": search_params,
             "limit": 5,
             "order": "rolling_rank DESC"
         })
         response = requests.get(url + "?" + data)
         if response.ok:
             if response.json():
                 tweet_positive_result(response, status)
             else:
                 tweet_random_result(status)
         else:
             response.raise_for_status()
     else:
         search_params['search'] = [status.text.replace("#marmomood", "")]
         data = urlencode({
             "q": search_params,
             "limit": 1,
             "order": "rolling_rank DESC"
         })
         response = requests.get(url + "?" + data)
         if response.ok:
             if response.json():
                 tweet_positive_result(response, status)
             else:
                 tweet_random_result(status)
         else:
             response.raise_for_status()
    def buildHttpQuery(self, taxonomy, parameters):
        if taxonomy.startswith('/'):
            taxonomy = taxonomy[1:]
        if not self.baseurl.endswith('/'):
            self.baseurl += '/'
        url = urljoin(self.baseurl, taxonomy)
        url_parts = list(urlparse(url))
        query = dict(parse_qsl(url_parts[4]))
        query.update(parameters)

        url_parts[4] = urlencode(query)

        url = urlunparse(url_parts)
        return url
Example #13
0
def tweet_random_result(status):
    data = urlencode({"limit": 10, "order": "rolling_rank DESC"})
    response = requests.get(url + "?" + data)
    if response.ok:
        if response.json():
            random_track = random.choice(response.tracks())
            message = '''@{0} I couldn't find that. Why don't you check out "{1}," it's one of our hottest songs: {2}'''.format(
                status.user.screen_name, random_track.title,
                shorten_url(random_track.url))
            api.update_status(shorten_message(message, random_track),
                              in_reply_to_status_id=status.id)
        else:
            message = "@{0} your search was so specific, I couldn't find anything. Please try again.".format(
                status.user.screen_name)
            api.update_status(message, in_reply_to_status_id=status.id)
    else:
        response.raise_for_status()
Example #14
0
    def prepare_batch(params):
        """
        Prepare methods for batch call
        :param params: dict
        :return: dict
        """
        if not isinstance(params, dict):
            raise Exception('Invalid \'cmd\' structure')

        batched_params = dict()

        for call_id in sorted(params.keys()):
            if not isinstance(params[call_id], list):
                raise Exception('Invalid \'cmd\' method description')
            method = params[call_id].pop(0)
            if method == 'batch':
                raise Exception('Batch call cannot contain batch methods')
            temp = ''
            for i in params[call_id]:
                temp += urlencode(i) + '&'
            batched_params[call_id] = method + '?' + temp

        return batched_params
Example #15
0
    def call(self,
             method,
             params1=None,
             params2=None,
             params3=None,
             params4=None):
        """Call Bitrix24 API method
        :param method: Method name
        :param params1: Method parameters 1
        :param params2: Method parameters 2. Needed for methods with determinate consequence of parameters
        :param params3: Method parameters 3. Needed for methods with determinate consequence of parameters
        :param params4: Method parameters 4. Needed for methods with determinate consequence of parameters
        :return: Call result
        """

        # Checking token exists
        if not self.access_token:
            if self.refresh_token:
                self.refresh_tokens()
            else:
                self.authenticate()

        if method == '' or not isinstance(method, str):
            raise Exception('Empty Method')

        if method == 'batch' and 'prepared' not in params1:
            params1['cmd'] = self.prepare_batch(params1['cmd'])
            params1['prepared'] = True

        encoded_parameters = ''

        # print params1
        for i in [
                params1, params2, params3, params4, {
                    'auth': self.access_token
                }
        ]:
            if i is not None:
                if 'cmd' in i:
                    i = dict(i)
                    encoded_parameters += self.encode_cmd(
                        i['cmd']) + '&' + urlencode({'halt': i['halt']}) + '&'
                else:
                    encoded_parameters += urlencode(i) + '&'
        r = {}

        try:
            # request url
            url = self.api_url % (self.domain, method)
            # Make API request
            r = requests.post(url,
                              data=encoded_parameters,
                              timeout=self.timeout)
            # Decode response
            result = r.json()
        except ValueError:
            result = dict(error='Error on decode api response [%s]' % r.text)
        except requests.ReadTimeout:
            result = dict(error='Timeout waiting expired [%s sec]' %
                          str(self.timeout))
        except requests.ConnectionError as e:
            print(e.request.url)
            print(e)
            result = dict(error='Max retries exceeded [1]')
        except (AuthenticationFailed, TokenRenewFailed) as e:
            result = e.result
            if 'error' in result:
                error_code = result['error']
                if error_code in ('invalid_token', 'NO_AUTH_FOUND',
                                  'expired_token'):
                    self.refresh_tokens()
                elif error_code in 'QUERY_LIMIT_EXCEEDED':
                    # Suspend call on two second, wait limitation time by Bitrix24 API
                    time.sleep(2)
                    return self.call(method, params1, params2, params3,
                                     params4)

                # Repeat API request after renew token
                result = self.call(method, params1, params2, params3, params4)

        return result
def test_basic():
    """Verify that urlencode works with four levels."""
    d = {"a": {"b": {"c": "d"}}}
    expected = urllib.quote("a[b][c]=d", safe="=/&")
    assert urlencode(d) == expected
def test_with_non_dict():
    """Verify that we raise an exception when passing a non-dict."""
    with pytest.raises(TypeError):
        urlencode("e")
def test_with_list_value():
    """Verify that urlencode works with list value."""
    d = {'a': {"b": [1, 2, 3]}}
    expected = "a[b][]=1&a[b][]=2&a[b][]=3"
    assert urllib.unquote(urlencode(d)) == expected
Example #19
0
def test_two():
    """Verify that urlencode works with two params."""
    d = {'a': 'b', 'c': {'d': 'e'}}
    expected = urllib.quote("a=b&c[d]=e", safe="=/&")
    assert urlencode(d) == expected
def test_no_array_braces():
    """Verify that array braces can be left off."""
    d = {'a': {"b": [1, 2, 3]}}
    expected = "a[b]=1&a[b]=2&a[b]=3"
    assert unquote(urlencode(d, array_braces=False)) == expected
Example #21
0
def test_with_list_value():
    """Verify that urlencode works with list value."""
    d = {'a': {"b": [1, 2, 3]}}
    expected = "a[b][]=1&a[b][]=2&a[b][]=3"
    assert unquote(urlencode(d)) == expected
Example #22
0
def test_key_types():
    """Verify that urlencode works with key type 'int'."""
    d = {1: {2: {3: 4}}}
    expected = quote("1[2][3]=4", safe="=/&")
    assert urlencode(d) == expected
def test_encode_list_key():
    """Verify that list indexes are explicitly added."""
    d = {'a': {"b": [1, 2, 3]}}
    expected = "a[b][0]=1&a[b][1]=2&a[b][2]=3"
    assert unquote(urlencode(d, encode_list_key=True)) == expected
Example #24
0
 def __await__(self):
     return self.api_call(self.url + urlencode(self.params)).__await__()
Example #25
0
    def __request(self,
                  type='GET',
                  content_type='application/json',
                  dry_run=False,
                  params={},
                  max_401_retry=3,
                  **kwargs):
        self.type = str.upper(type)

        if dry_run is True:
            logging.debug("This is a dry run mode, skipping %s %s" %
                          (self.type, self.endpoint))
            logging.debug("Parameters: %s" % params)
            return "{'message': 'Dry-run mode, request " "%s %s skipped'}" % (
                self.type, self.endpoint)

        logging.debug('%s %s' % (self.type, self.endpoint))
        if params is not None:
            logging.debug('Input params: %s' % params)

        request_arguments = {
            'params': params.copy(),
            'verify': False,
            'data': {}
        }
        if 'metaData' in request_arguments['params']:
            request_arguments['params']['metaData'] = json.dumps(
                request_arguments['params']['metaData'])

        if 'complex' in request_arguments['params']:
            try:
                from multidimensional_urlencode import urlencode
                logging.debug('complex key found, doing dirty stuff...')
                complex = urlencode(
                    {'complex': request_arguments['params']['complex']})
                self.endpoint += '?%s' % complex
                del (request_arguments['params']['complex'])
            except ImportError as e:
                logging.debug(
                    "Unable to handle complex key, missing or"
                    "failed to load multidimensionnal_urlencode: %s" % e)
                raise ValueError("Unable to handle complex filter")

        # XXX: To simplify method calling we only support 'params' as keyword.
        # In case of POST/PUT/DELETE we set params as 'data' keyword of
        # requests library. In case of file uploading, symbolised by the
        # presence of 'files' keyword we let params because contacts API does
        # not support files upload (POST) with parameters in body.
        if self.type.upper() != 'GET' and 'files' not in kwargs:
            action = None
            if 'action' in request_arguments['params']:
                action = request_arguments['params']['action']
                del (request_arguments['params']['action'])

            request_arguments['data'] = json.dumps(
                dict(request_arguments['data'],
                     **request_arguments.pop('params')))
            request_arguments['headers'] = {'Content-type': content_type}

            if action is not None:
                logging.debug("Forcing action parameter to be passed in "
                              "request URL")
                request_arguments['params'] = {'action': action}

        arguments = dict(
            list(request_arguments.items()) + list(kwargs.items()))

        if self.auth is not None:
            arguments['auth'] = self.auth

        logging.debug("Requests args: %s" % arguments)
        response = getattr(requests, str.lower(self.type))(self.endpoint,
                                                           **arguments)
        logging.debug("URL: %s" % response.url)

        try:
            # Raise an exception onr 4xx, 5xx HTTPError
            response.raise_for_status()
        except Exception as e:

            def process_http_response(response):
                if response.status_code == 500:
                    error = '{"status": 500, "message": "Internal Server '\
                        'Error"}'
                else:
                    error = json.loads(response.text)

                if 'message' in error:
                    details = ""
                    if 'details' in error:
                        details = "(%s)" % error['details']

                    message = "HTTP code <%s>: %s %s" % (response.status_code,
                                                         error, details)
                else:  # this is an internal error
                    message = e.message

                return message

            # manage  401
            if response.status_code == 401:
                retry = max_401_retry - 1
                logging.debug("401 'Unauthorized' status code returned, "
                              "retrying a maximum of %s times" % max_401_retry)
                while response.status_code == 401 and retry >= 0:
                    if hasattr(self.auth, 'token'):
                        logging.debug("It looks like authentication mecanism "
                                      "uses token")
                        self.auth.token.expire()

                    response = getattr(requests,
                                       str.lower(self.type))(self.url,
                                                             **arguments)
                    logging.debug("Retry %s/%s: call to %s returned %s" %
                                  (max_401_retry - retry, max_401_retry,
                                   response.url, response.status_code))
                    retry -= 1
                try:
                    response.raise_for_status()
                except Exception as e:
                    message = process_http_response(response)
                    logging.debug(message)
                    raise Exception(message)
            else:
                message = process_http_response(response)
                raise Exception(message)

        logging.debug("HTTP code <%s>: OK" % response.status_code)

        text = response.text or '{}'
        return json.loads(text)
Example #26
0
 def list_comments(self, **kwargs):
     for key in kwargs:
         if key not in ['article_id', '_fields', 'sort', 'limit']:
             raise InvalidArg(key)
     return self.__call(self.knowledgeowl.comment, 'GET', params=urlencode(kwargs))
Example #27
0
 def list_readerroles(self, _fields=None, sort=None, limit=None, **params):
     for key in kwargs:
         if key not in READERROLES_KEYS or key not in ['_fields', 'sort', 'limit']:
             raise InvalidArg(key)
     kwargs['project_id'] = self.project_id
     return self.__call(self.knowledgeowl.readerroles, 'GET', params=urlencode(kwargs))
Example #28
0
 def get_readerroles(self, role_id, **kwargs):
     for key in kwargs:
         if key not in ['_fields']:
             raise InvalidArg(key)
     kwargs['project_id'] = self.project_id
     return self.__call(self.knowledgeowl.readerroles(role_id), 'GET', params=urlencode(kwargs))
Example #29
0
def test_basic():
    """Verify that urlencode works with four levels."""
    d = {"a": {"b": {"c": "d"}}}
    expected = quote("a[b][c]=d", safe="=/&")
    assert urlencode(d) == expected
Example #30
0
 def explain(self, endpoint):
     self.__call(self.knowledgeowl(endpoint), 'GET', params=urlencode({'_method': 'explain'}))
Example #31
0
def test_two():
    """Verify that urlencode works with two params."""
    d = {'a': 'b', 'c': {'d': 'e'}}
    expected = quote("a=b&c[d]=e", safe="=/&")
    assert '&'.join(urlencode(d).split('&')) == expected
def test_key_types():
    """Verify that urlencode works with key type 'int'."""
    d = {1: {2: {3: 4}}}
    expected = urllib.quote("1[2][3]=4", safe="=/&")
    assert urlencode(d) == expected
Example #33
0
def test_with_non_dict():
    """Verify that we raise an exception when passing a non-dict."""
    with pytest.raises(TypeError):
        urlencode("e")
Example #34
0
    def __request(self, type='GET', content_type='application/json',
                  dry_run=False, params={}, max_401_retry=3, **kwargs):
        self.type = str.upper(type)

        if dry_run is True:
            logging.debug("This is a dry run mode, skipping %s %s" % (
                self.type, self.endpoint))
            logging.debug("Parameters: %s" % params)
            return "{'message': 'Dry-run mode, request " "%s %s skipped'}" % (
                self.type, self.endpoint)

        logging.debug('%s %s' % (self.type, self.endpoint))
        if params is not None:
            logging.debug('Input params: %s' % params)

        request_arguments = {'params': params.copy(), 'verify': False,
                             'data': {}}
        if 'metaData' in request_arguments['params']:
            request_arguments['params']['metaData'] = json.dumps(
                request_arguments['params']['metaData'])

        if 'complex' in request_arguments['params']:
            try:
                from multidimensional_urlencode import urlencode
                logging.debug('complex key found, doing dirty stuff...')
                complex = urlencode({
                    'complex': request_arguments['params']['complex']})
                self.endpoint += '?%s' % complex
                del(request_arguments['params']['complex'])
            except ImportError as e:
                logging.debug("Unable to handle complex key, missing or"
                              "failed to load multidimensionnal_urlencode: %s"
                              % e)
                raise ValueError("Unable to handle complex filter")

        # XXX: To simplify method calling we only support 'params' as keyword.
        # In case of POST/PUT/DELETE we set params as 'data' keyword of
        # requests library. In case of file uploading, symbolised by the
        # presence of 'files' keyword we let params because contacts API does
        # not support files upload (POST) with parameters in body.
        if self.type.upper() != 'GET' and 'files' not in kwargs:
            action = None
            if 'action' in request_arguments['params']:
                action = request_arguments['params']['action']
                del(request_arguments['params']['action'])

            request_arguments['data'] = json.dumps(
                dict(
                    request_arguments['data'],
                    **request_arguments.pop('params')
                ))
            request_arguments['headers'] = {'Content-type': content_type}

            if action is not None:
                logging.debug("Forcing action parameter to be passed in "
                              "request URL")
                request_arguments['params'] = {'action': action}

        arguments = dict(list(request_arguments.items()) +
                         list(kwargs.items()))

        if self.auth is not None:
            arguments['auth'] = self.auth

        logging.debug("Requests args: %s" % arguments)
        response = getattr(requests, str.lower(self.type))(
            self.endpoint, **arguments)
        logging.debug("URL: %s" % response.url)

        try:
            # Raise an exception onr 4xx, 5xx HTTPError
            response.raise_for_status()
        except Exception as e:

            def process_http_response(response):
                if response.status_code == 500:
                    error = '{"status": 500, "message": "Internal Server '\
                        'Error"}'
                else:
                    error = json.loads(response.text)

                if 'message' in error:
                    details = ""
                    if 'details' in error:
                        details = "(%s)" % error['details']

                    message = "HTTP code <%s>: %s %s" % (response.status_code,
                                                         error,
                                                         details)
                else:  # this is an internal error
                    message = e.message

                return message

            # manage  401
            if response.status_code == 401:
                retry = max_401_retry - 1
                logging.debug("401 'Unauthorized' status code returned, "
                              "retrying a maximum of %s times" % max_401_retry)
                while response.status_code == 401 and retry >= 0:
                    if hasattr(self.auth, 'token'):
                        logging.debug("It looks like authentication mecanism "
                                      "uses token")
                        self.auth.token.expire()

                    response = getattr(requests, str.lower(self.type))(
                        self.url, **arguments)
                    logging.debug("Retry %s/%s: call to %s returned %s"
                                  % (
                                      max_401_retry - retry,
                                      max_401_retry,
                                      response.url,
                                      response.status_code
                                  ))
                    retry -= 1
                try:
                    response.raise_for_status()
                except Exception as e:
                    message = process_http_response(response)
                    logging.debug(message)
                    raise Exception(message)
            else:
                message = process_http_response(response)
                raise Exception(message)

        logging.debug("HTTP code <%s>: OK" % response.status_code)

        text = response.text or '{}'
        return json.loads(text)