commit ebb3de86c9af92001845f3560f857615e1f633eb Author: Damian Johnson atagar@torproject.org Date: Sat Oct 27 19:32:43 2012 -0700
Revised API docs for stem.response
This is a little different from the other modules in that we're including stem.response.__init__ as an automodule then autoclasses for all of the contents. The response classes each have precious little documentation to having them each on their own page would be pointless.
Also moving the AuthMethod enum to the connection so we can drop the protocolinfo module documentation (it wouldn't be included since we're using autoclass). --- docs/api.rst | 1 + docs/api/response.rst | 14 ++++++ docs/contents.rst | 1 + stem/connection.py | 26 ++++++++++- stem/response/__init__.py | 99 ++++++++++++++++++++++------------------- stem/response/getconf.py | 3 +- stem/response/protocolinfo.py | 30 +------------ 7 files changed, 97 insertions(+), 77 deletions(-)
diff --git a/docs/api.rst b/docs/api.rst index c138240..e149c81 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -10,6 +10,7 @@ Controller * `stem.connection <api/connection.html>`_ - Connection and authentication to the Tor control port or socket. * `stem.socket <api/socket.html>`_ - Low level control socket used to talk with Tor. * `stem.process <api/process.html>`_ - Launcher for the Tor process. + * `stem.response <api/response.html>`_ - Messages that Tor may provide the controller.
* **Types**
diff --git a/docs/api/response.rst b/docs/api/response.rst new file mode 100644 index 0000000..bf3b722 --- /dev/null +++ b/docs/api/response.rst @@ -0,0 +1,14 @@ +Controller Responses +==================== + +.. automodule:: stem.response + +Responses +--------- + +.. autoclass:: stem.response.authchallenge.AuthChallengeResponse +.. autoclass:: stem.response.getconf.GetConfResponse +.. autoclass:: stem.response.getinfo.GetInfoResponse +.. autoclass:: stem.response.mapaddress.MapAddressResponse +.. autoclass:: stem.response.protocolinfo.ProtocolInfoResponse + diff --git a/docs/contents.rst b/docs/contents.rst index 03274a4..6b0311c 100644 --- a/docs/contents.rst +++ b/docs/contents.rst @@ -12,6 +12,7 @@ Contents api/connection api/socket api/process + api/response
api/exit_policy api/version diff --git a/stem/connection.py b/stem/connection.py index 730ad27..edad9d8 100644 --- a/stem/connection.py +++ b/stem/connection.py @@ -42,6 +42,29 @@ fine-grained control over the authentication process. For instance... print "Unable to authenticate: %s" % exc sys.exit(1)
+The AuthMethod enumeration includes methods by which a controller can +authenticate to the control port. Tor gives a list of all the authentication +methods it will accept in response to PROTOCOLINFO queries. + +**AuthMethod.NONE** + No authentication required + +**AuthMethod.PASSWORD** + See tor's HashedControlPassword option. Controllers must provide the password + used to generate the hash. + +**AuthMethod.COOKIE** + See tor's CookieAuthentication option. Controllers need to supply the + contents of the cookie file. + +**AuthMethod.SAFECOOKIE** + See tor's CookieAuthentication option. Controllers need to reply to a + hmac challenge using the contents of the cookie file. + +**AuthMethod.UNKNOWN** + Tor provided one or more authentication methods that we don't recognize. This + is probably from a new addition to the control protocol. + **Module Overview:**
:: @@ -99,7 +122,8 @@ import stem.util.enum import stem.util.system import stem.util.connection import stem.util.log as log -from stem.response.protocolinfo import AuthMethod + +AuthMethod = stem.util.enum.Enum("NONE", "PASSWORD", "COOKIE", "SAFECOOKIE", "UNKNOWN")
CLIENT_HASH_CONSTANT = "Tor safe cookie authentication controller-to-server hash" SERVER_HASH_CONSTANT = "Tor safe cookie authentication server-to-controller hash" diff --git a/stem/response/__init__.py b/stem/response/__init__.py index 4a05be2..5c9b889 100644 --- a/stem/response/__init__.py +++ b/stem/response/__init__.py @@ -54,9 +54,10 @@ CONTROL_ESCAPES = {r"\": "\", r""": """, r"'": "'",
def convert(response_type, message, **kwargs): """ - Converts a ControlMessage into a particular kind of tor response. This does - an in-place conversion of the message from being a ControlMessage to a - subclass for its response type. Recognized types include... + Converts a :class:`~stem.response.ControlMessage` into a particular kind of + tor response. This does an in-place conversion of the message from being a + :class:`~stem.response.ControlMessage` to a subclass for its response type. + Recognized types include...
* ***** GETINFO * ***** GETCONF @@ -65,19 +66,23 @@ def convert(response_type, message, **kwargs): * AUTHCHALLENGE * SINGLELINE
- ***** can raise a :class:`stem.socket.InvalidArguments` exception - **^** can raise a :class:`stem.socket.InvalidRequest` exception - **&** can raise a :class:`stem.socket.OperationFailed` exception + * ***** can raise a :class:`stem.socket.InvalidArguments` exception + * **^** can raise a :class:`stem.socket.InvalidRequest` exception + * **&** can raise a :class:`stem.socket.OperationFailed` exception
:param str response_type: type of tor response to convert to :param stem.response.ControlMessage message: message to be converted :param kwargs: optional keyword arguments to be passed to the parser method
:raises: - * :class:`stem.socket.ProtocolError` the message isn't a proper response of that type - * :class:`stem.socket.InvalidArguments` the arguments given as input are invalid - * :class:`stem.socket.InvalidRequest` the arguments given as input are invalid - * TypeError if argument isn't a :class:`stem.response.ControlMessage` or response_type isn't supported + * :class:`stem.socket.ProtocolError` the message isn't a proper response of + that type + * :class:`stem.socket.InvalidArguments` the arguments given as input are + invalid + * :class:`stem.socket.InvalidRequest` the arguments given as input are + invalid + * **TypeError** if argument isn't a :class:`~stem.response.ControlMessage` + or response_type isn't supported """
import stem.response.getinfo @@ -124,7 +129,7 @@ class ControlMessage(object): """ Checks if any of our lines have a 250 response.
- :returns: True if any lines have a 250 response code, False otherwise + :returns: **True** if any lines have a 250 response code, **False** otherwise """
for code, _, _ in self._parsed_content: @@ -154,7 +159,7 @@ class ControlMessage(object): For data entries the content is the full multi-line payload with newline linebreaks and leading periods unescaped.
- :returns: list of (str, str, str) tuples for the components of this message + :returns: **list** of (str, str, str) tuples for the components of this message """
return list(self._parsed_content) @@ -163,7 +168,7 @@ class ControlMessage(object): """ Provides the unparsed content read from the control socket.
- :returns: string of the socket data used to generate this message + :returns: **str** of the socket data used to generate this message """
return self._raw_content @@ -178,8 +183,8 @@ class ControlMessage(object):
def __iter__(self): """ - Provides ControlLine instances for the content of the message. This is - stripped of status codes and dividers, for instance... + Provides :class:`~stem.response.ControlLine` instances for the content of + the message. This is stripped of status codes and dividers, for instance...
::
@@ -204,14 +209,14 @@ class ControlMessage(object):
def __len__(self): """ - :returns: Number of ControlLines + :returns: number of ControlLines """
return len(self._parsed_content)
def __getitem__(self, index): """ - :returns: ControlLine at index + :returns: :class:`~stem.response.ControlLine` at the index """
return ControlLine(self._parsed_content[index][2]) @@ -238,7 +243,7 @@ class ControlLine(str): Provides our unparsed content. This is an empty string after we've popped all entries.
- :returns: str of the unparsed content + :returns: **str** of the unparsed content """
return self._remainder @@ -247,7 +252,7 @@ class ControlLine(str): """ Checks if we have further content to pop or not.
- :returns: True if we have additional content, False otherwise + :returns: **True** if we have additional content, **False** otherwise """
return self._remainder == "" @@ -256,9 +261,9 @@ class ControlLine(str): """ Checks if our next entry is a quoted value or not.
- :param bool escaped: unescapes the ``CONTROL_ESCAPES`` escape sequences + :param bool escaped: unescapes the CONTROL_ESCAPES escape sequences
- :returns: True if the next entry can be parsed as a quoted value, False otherwise + :returns: **True** if the next entry can be parsed as a quoted value, **False** otherwise """
start_quote, end_quote = _get_quote_indeces(self._remainder, escaped) @@ -268,11 +273,12 @@ class ControlLine(str): """ Checks if our next entry is a KEY=VALUE mapping or not.
- :param str key: checks that the key matches this value, skipping the check if ``None`` + :param str key: checks that the key matches this value, skipping the check if **None** :param bool quoted: checks that the mapping is to a quoted value - :param bool escaped: unescapes the ``CONTROL_ESCAPES`` escape sequences + :param bool escaped: unescapes the CONTROL_ESCAPES escape sequences
- :returns: True if the next entry can be parsed as a key=value mapping, False otherwise + :returns: **True** if the next entry can be parsed as a key=value mapping, + **False** otherwise """
remainder = self._remainder # temp copy to avoid locking @@ -293,10 +299,10 @@ class ControlLine(str):
def peek_key(self): """ - Provides the key of the next entry, providing None if it isn't a key/value - mapping. + Provides the key of the next entry, providing **None** if it isn't a + key/value mapping.
- :returns: str with the next entry's key + :returns: **str** with the next entry's key """
remainder = self._remainder @@ -327,13 +333,13 @@ class ControlLine(str): "this has a \" and \\ in it"
:param bool quoted: parses the next entry as a quoted value, removing the quotes - :param bool escaped: unescapes the ``CONTROL_ESCAPES`` escape sequences + :param bool escaped: unescapes the CONTROL_ESCAPES escape sequences
- :returns: str of the next space separated entry + :returns: **str** of the next space separated entry
:raises: - * ValueError if quoted is True without the value being quoted - * IndexError if we don't have any remaining content left to parse + * **ValueError** if quoted is True without the value being quoted + * **IndexError** if we don't have any remaining content left to parse """
with self._remainder_lock: @@ -347,12 +353,13 @@ class ControlLine(str): and the space from our remaining content.
:param bool quoted: parses the value as being quoted, removing the quotes - :param bool escaped: unescapes the ``CONTROL_ESCAPES`` escape sequences + :param bool escaped: unescapes the CONTROL_ESCAPES escape sequences
- :returns: tuple of the form (key, value) + :returns: **tuple** of the form (key, value)
- :raises: ValueError if this isn't a KEY=VALUE mapping or if quoted is True without the value being quoted - :raises: IndexError if there's nothing to parse from the line + :raises: **ValueError** if this isn't a KEY=VALUE mapping or if quoted is + **True** without the value being quoted + :raises: **IndexError** if there's nothing to parse from the line """
with self._remainder_lock: @@ -376,13 +383,13 @@ def _parse_entry(line, quoted, escaped):
:param str line: content to be parsed :param bool quoted: parses the next entry as a quoted value, removing the quotes - :param bool escaped: unescapes the ``CONTROL_ESCAPES`` escape sequences + :param bool escaped: unescapes the CONTROL_ESCAPES escape sequences
- :returns: tuple of the form (entry, remainder) + :returns: **tuple** of the form (entry, remainder)
:raises: - * ValueError if quoted is True without the next value being quoted - * IndexError if there's nothing to parse from the line + * **ValueError** if quoted is True without the next value being quoted + * **IndexError** if there's nothing to parse from the line """
if line == "": @@ -414,9 +421,9 @@ def _get_quote_indeces(line, escaped): Provides the indices of the next two quotes in the given content.
:param str line: content to be parsed - :param bool escaped: unescapes the ``CONTROL_ESCAPES`` escape sequences + :param bool escaped: unescapes the CONTROL_ESCAPES escape sequences
- :returns: tuple of two ints, indices being -1 if a quote doesn't exist + :returns: **tuple** of two ints, indices being -1 if a quote doesn't exist """
indices, quote_index = [], -1 @@ -446,14 +453,14 @@ class SingleLineResponse(ControlMessage):
def is_ok(self, strict = False): """ - Checks if the response code is "250". If strict is True, checks if the - response is "250 OK" + Checks if the response code is "250". If strict is **True** then this + checks if the response is "250 OK"
- :param bool strict: checks for a "250 OK" message if True + :param bool strict: checks for a "250 OK" message if **True**
:returns: - * If strict is False: True if the response code is "250", False otherwise - * If strict is True: True if the response is "250 OK", False otherwise + * If strict is **False**: **True** if the response code is "250", **False** otherwise + * If strict is **True**: **True** if the response is "250 OK", **False** otherwise """
if strict: diff --git a/stem/response/getconf.py b/stem/response/getconf.py index 627e7bc..72bfc34 100644 --- a/stem/response/getconf.py +++ b/stem/response/getconf.py @@ -8,7 +8,8 @@ class GetConfResponse(stem.response.ControlMessage): Note that configuration parameters won't match what we queried for if it's one of the special mapping options (ex. "HiddenServiceOptions").
- :var dict entries: mapping between the config parameter (str) and their values (list of str) + :var dict entries: mapping between the config parameter (**str**) and their + values (**list** of **str**) """
def _parse_message(self): diff --git a/stem/response/protocolinfo.py b/stem/response/protocolinfo.py index eccad88..258c5b6 100644 --- a/stem/response/protocolinfo.py +++ b/stem/response/protocolinfo.py @@ -1,37 +1,9 @@ -""" -Parses replies to a tor PROTOCOLINFO queries. - -The AuthMethod enumeration includes methods by which a controller can -authenticate to the control port. Tor gives a list of all the authentication -methods it will accept in response to PROTOCOLINFO queries. - -**AuthMethod.NONE** - No authentication required - -**AuthMethod.PASSWORD** - See tor's HashedControlPassword option. Controllers must provide the password - used to generate the hash. - -**AuthMethod.COOKIE** - See tor's CookieAuthentication option. Controllers need to supply the - contents of the cookie file. - -**AuthMethod.SAFECOOKIE** - See tor's CookieAuthentication option. Controllers need to reply to a - hmac challenge using the contents of the cookie file. - -**AuthMethod.UNKNOWN** - Tor provided one or more authentication methods that we don't recognize. This - is probably from a new addition to the control protocol. -""" - import stem.socket import stem.response import stem.version -import stem.util.enum import stem.util.log as log
-AuthMethod = stem.util.enum.Enum("NONE", "PASSWORD", "COOKIE", "SAFECOOKIE", "UNKNOWN") +from stem.connection import AuthMethod
class ProtocolInfoResponse(stem.response.ControlMessage): """
tor-commits@lists.torproject.org