docs: 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)