def call()

in pygenie/utils.py [0:0]


def call(url, method='get', headers=None, raise_not_status=None, none_on_404=False,
         auth_handler=None, failure_codes=None, attempts=7, backoff=5, *args,
         **kwargs):
    """
    Wrap HTTP request calls to the Genie server.

    The request header will be updated to include 'user-agent'. If headers are
    passed in with 'user-agent', it will be overwritten.

    Args:
        method (str): the HTTP method to make
        headers (dict): headers to pass in during the request
        raise_not_status (int): raise GenieHTTPError if this status is not
            returned by genie.
        none_on_404 (bool): return None if a 404 if returned instead of raising
            GenieHTTPError (will not retry requests with 404 response).
        failure_codes (list, optional): list of status codes to break retries and
            return Response.
    """

    failure_codes = failure_codes or list()

    assert isinstance(failure_codes, (list, int)), \
        'failure_codes should be an int or list of ints'

    if isinstance(failure_codes, int):
        failure_codes = [failure_codes]

    failure_codes = [str(f) for f in failure_codes]

    if none_on_404 and '404' not in failure_codes:
        failure_codes.append('404')

    auth_handler = auth_handler or AuthHandler()

    headers = USER_AGENT_HEADER if headers is None \
        else dict(headers, **USER_AGENT_HEADER)

    logger.debug('"%s %s"', method.upper(), url)
    logger.debug('headers: %s', headers)

    errors = list()
    session = requests.Session()
    adapters = kwargs.pop('session_adapters', None) or {}
    for m, adpt in adapters.items():
        session.mount(m, adpt)

    for i in range(attempts):
        try:
            resp = session.request(method,
                                   url=url,
                                   headers=headers,
                                   auth=auth_handler.auth,
                                   *args,
                                   **kwargs)
            if (int(resp.status_code/100) == 2) or (str(resp.status_code) in failure_codes):
                break
        except (ConnectionError, Timeout, socket.timeout) as err:
            errors.append(err)
            resp = None

        if i < attempts - 1:
            msg = ''
            if resp is not None:
                msg = '-> {method} {url} ({code}): {text}'\
                    .format(method=resp.request.method,
                            url=resp.url,
                            code=resp.status_code,
                            text=resp.content)
            logger.warning('attempt %s %s', i + 1, msg)
            time.sleep(i * backoff)

    if resp is not None:
        # Allow us to return None if we receive a 404
        if resp.status_code == 404 and none_on_404:
            return None

        if not resp.ok:
            raise GenieHTTPError(resp)

        # Raise GenieHTTPError if a particular status code was not returned
        if raise_not_status and resp.status_code != raise_not_status:
            raise GenieHTTPError(resp)

        return resp
    elif len(errors) > 0:
        raise errors[-1]