docs: def fromMessage(klass, message, op_endpoint):
          """Construct me from an OpenID message.
  
          @raises ProtocolError: When not all required parameters are present
              in the message.
  
          @raises MalformedReturnURL: When the C{return_to} URL is not a URL.
  
          @raises UntrustedReturnURL: When the C{return_to} URL is outside
              the C{trust_root}.
  
          @param message: An OpenID checkid_* request Message
          @type message: openid.message.Message
  
          @param op_endpoint: The endpoint URL of the server that this
              message was sent to.
          @type op_endpoint: str
  
          @returntype: L{CheckIDRequest}
          """
          self = klass.__new__(klass)
          self.message = message
          self.op_endpoint = op_endpoint
          mode = message.getArg(OPENID_NS, 'mode')
          if mode == "checkid_immediate":
              self.immediate = True
              self.mode = "checkid_immediate"
          else:
              self.immediate = False
              self.mode = "checkid_setup"
  
          self.return_to = message.getArg(OPENID_NS, 'return_to')
          if message.isOpenID1() and not self.return_to:
              fmt = "Missing required field 'return_to' from %r"
              raise ProtocolError(message, text=fmt % (message,))
  
          self.identity = message.getArg(OPENID_NS, 'identity')
          self.claimed_id = message.getArg(OPENID_NS, 'claimed_id')
          if message.isOpenID1():
              if self.identity is None:
                  s = "OpenID 1 message did not contain openid.identity"
                  raise ProtocolError(message, text=s)
          else:
              if self.identity and not self.claimed_id:
                  s = ("OpenID 2.0 message contained openid.identity but not "
                       "claimed_id")
                  raise ProtocolError(message, text=s)
              elif self.claimed_id and not self.identity:
                  s = ("OpenID 2.0 message contained openid.claimed_id but not "
                       "identity")
                  raise ProtocolError(message, text=s)
  
          # There's a case for making self.trust_root be a TrustRoot
          # here.  But if TrustRoot isn't currently part of the "public" API,
          # I'm not sure it's worth doing.
  
          if message.isOpenID1():
              trust_root_param = 'trust_root'
          else:
              trust_root_param = 'realm'
  
          # Using 'or' here is slightly different than sending a default
          # argument to getArg, as it will treat no value and an empty
          # string as equivalent.
          self.trust_root = (message.getArg(OPENID_NS, trust_root_param)
                             or self.return_to)
  
          if not message.isOpenID1():
              if self.return_to is self.trust_root is None:
                  raise ProtocolError(message, "openid.realm required when " +
                                      "openid.return_to absent")
  
          self.assoc_handle = message.getArg(OPENID_NS, 'assoc_handle')
  
          # Using TrustRoot.parse here is a bit misleading, as we're not
          # parsing return_to as a trust root at all.  However, valid URLs
          # are valid trust roots, so we can use this to get an idea if it
          # is a valid URL.  Not all trust roots are valid return_to URLs,
          # however (particularly ones with wildcards), so this is still a
          # little sketchy.
          if self.return_to is not None and \
                 not TrustRoot.parse(self.return_to):
              raise MalformedReturnURL(message, self.return_to)
  
          # I first thought that checking to see if the return_to is within
          # the trust_root is premature here, a logic-not-decoding thing.  But
          # it was argued that this is really part of data validation.  A
          # request with an invalid trust_root/return_to is broken regardless of
          # application, right?
          if not self.trustRootValid():
              raise UntrustedReturnURL(message, self.return_to, self.trust_root)
  
          return self