Log `username` into the MemberSuite Portal.

    Returns a PortalUser object if successful, raises
    LoginToPortalError if not.

    Will retry logging in if a GeneralException occurs, up to `retries`.
    Will pause `delay` seconds between retries.

def login_to_portal(username, password, client, retries=2, delay=0):
    """Log `username` into the MemberSuite Portal.

    Returns a PortalUser object if successful, raises
    LoginToPortalError if not.

    Will retry logging in if a GeneralException occurs, up to `retries`.
    Will pause `delay` seconds between retries.
    """
    if not client.session_id:
        client.request_session()

    concierge_request_header = client.construct_concierge_header(
        url=("http://membersuite.com/contracts/IConciergeAPIService/"
             "LoginToPortal"))

    attempts = 0
    while attempts < retries:
        if attempts:
            time.sleep(delay)

        result = client.client.service.LoginToPortal(
            _soapheaders=[concierge_request_header],
            portalUserName=username,
            portalPassword=password)

        login_to_portal_result = result["body"]["LoginToPortalResult"]

        if login_to_portal_result["Success"]:
            portal_user = login_to_portal_result["ResultValue"]["PortalUser"]

            session_id = get_session_id(result=result)

            return PortalUser(membersuite_object_data=portal_user,
                              session_id=session_id)
        else:
            attempts += 1
            try:
                error_code = login_to_portal_result[
                    "Errors"]["ConciergeError"][0]["Code"]
            except IndexError:  # Not a ConciergeError
                continue
            else:
                if attempts < retries and error_code == "GeneralException":
                    continue

    raise LoginToPortalError(result=result)