tor-commits
Threads by month
- ----- 2025 -----
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
June 2012
- 17 participants
- 880 discussions
commit feeac963d1383b9eb5a08251dbd329ff64f1b846
Author: Damian Johnson <atagar(a)torproject.org>
Date: Thu May 31 09:57:51 2012 -0700
Initial sphinx autogenerated content
Results right after running 'sphinx-quickstart'
---
docs/Makefile | 130 ++++++++++++++++++++++++++++++++++
docs/conf.py | 216 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
docs/index.rst | 20 +++++
docs/make.bat | 155 ++++++++++++++++++++++++++++++++++++++++
4 files changed, 521 insertions(+), 0 deletions(-)
diff --git a/docs/Makefile b/docs/Makefile
new file mode 100644
index 0000000..9c6e6d3
--- /dev/null
+++ b/docs/Makefile
@@ -0,0 +1,130 @@
+# Makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line.
+SPHINXOPTS =
+SPHINXBUILD = sphinx-build
+PAPER =
+BUILDDIR = _build
+
+# Internal variables.
+PAPEROPT_a4 = -D latex_paper_size=a4
+PAPEROPT_letter = -D latex_paper_size=letter
+ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
+
+.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest
+
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " html to make standalone HTML files"
+ @echo " dirhtml to make HTML files named index.html in directories"
+ @echo " singlehtml to make a single large HTML file"
+ @echo " pickle to make pickle files"
+ @echo " json to make JSON files"
+ @echo " htmlhelp to make HTML files and a HTML help project"
+ @echo " qthelp to make HTML files and a qthelp project"
+ @echo " devhelp to make HTML files and a Devhelp project"
+ @echo " epub to make an epub"
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
+ @echo " text to make text files"
+ @echo " man to make manual pages"
+ @echo " changes to make an overview of all changed/added/deprecated items"
+ @echo " linkcheck to check all external links for integrity"
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
+
+clean:
+ -rm -rf $(BUILDDIR)/*
+
+html:
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
+
+dirhtml:
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ @echo
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
+
+singlehtml:
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ @echo
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
+
+pickle:
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ @echo
+ @echo "Build finished; now you can process the pickle files."
+
+json:
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ @echo
+ @echo "Build finished; now you can process the JSON files."
+
+htmlhelp:
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ @echo
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
+
+qthelp:
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ @echo
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Stem.qhcp"
+ @echo "To view the help file:"
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Stem.qhc"
+
+devhelp:
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+ @echo
+ @echo "Build finished."
+ @echo "To view the help file:"
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/Stem"
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Stem"
+ @echo "# devhelp"
+
+epub:
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ @echo
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
+
+latex:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
+ "(use \`make latexpdf' here to do that automatically)."
+
+latexpdf:
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ @echo "Running LaTeX files through pdflatex..."
+ make -C $(BUILDDIR)/latex all-pdf
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
+
+text:
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ @echo
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
+
+man:
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ @echo
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
+
+changes:
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ @echo
+ @echo "The overview file is in $(BUILDDIR)/changes."
+
+linkcheck:
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ @echo
+ @echo "Link check complete; look for any errors in the above output " \
+ "or in $(BUILDDIR)/linkcheck/output.txt."
+
+doctest:
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ @echo "Testing of doctests in the sources finished, look at the " \
+ "results in $(BUILDDIR)/doctest/output.txt."
diff --git a/docs/conf.py b/docs/conf.py
new file mode 100644
index 0000000..1a4ab26
--- /dev/null
+++ b/docs/conf.py
@@ -0,0 +1,216 @@
+# -*- coding: utf-8 -*-
+#
+# Stem documentation build configuration file, created by
+# sphinx-quickstart on Thu May 31 09:56:13 2012.
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# Note that not all possible configuration values are present in this
+# autogenerated file.
+#
+# All configuration values have a default; values that are commented out
+# serve to show the default.
+
+import sys, os
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#sys.path.insert(0, os.path.abspath('.'))
+
+# -- General configuration -----------------------------------------------------
+
+# If your documentation needs a minimal Sphinx version, state it here.
+#needs_sphinx = '1.0'
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The encoding of source files.
+#source_encoding = 'utf-8-sig'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General information about the project.
+project = u'Stem'
+copyright = u'2012, Damian Johnson'
+
+# The version info for the project you're documenting, acts as replacement for
+# |version| and |release|, also used in various other places throughout the
+# built documents.
+#
+# The short X.Y version.
+version = '0.0'
+# The full version, including alpha/beta/rc tags.
+release = '0.0.1'
+
+# The language for content autogenerated by Sphinx. Refer to documentation
+# for a list of supported languages.
+#language = None
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+#today_fmt = '%B %d, %Y'
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+exclude_patterns = ['_build']
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+# A list of ignored prefixes for module index sorting.
+#modindex_common_prefix = []
+
+
+# -- Options for HTML output ---------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+html_theme = 'default'
+
+# Theme options are theme-specific and customize the look and feel of a theme
+# further. For a list of options available for each theme, see the
+# documentation.
+#html_theme_options = {}
+
+# Add any paths that contain custom themes here, relative to this directory.
+#html_theme_path = []
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (relative to this directory) to place at the top
+# of the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+#html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+#html_domain_indices = True
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, links to the reST sources are added to the pages.
+#html_show_sourcelink = True
+
+# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
+#html_show_sphinx = True
+
+# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
+#html_show_copyright = True
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# This is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = None
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'Stemdoc'
+
+
+# -- Options for LaTeX output --------------------------------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, documentclass [howto/manual]).
+latex_documents = [
+ ('index', 'Stem.tex', u'Stem Documentation',
+ u'Damian Johnson', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# If true, show page references after internal links.
+#latex_show_pagerefs = False
+
+# If true, show URL addresses after external links.
+#latex_show_urls = False
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_domain_indices = True
+
+
+# -- Options for manual page output --------------------------------------------
+
+# One entry per manual page. List of tuples
+# (source start file, name, description, authors, manual section).
+man_pages = [
+ ('index', 'stem', u'Stem Documentation',
+ [u'Damian Johnson'], 1)
+]
diff --git a/docs/index.rst b/docs/index.rst
new file mode 100644
index 0000000..8434a81
--- /dev/null
+++ b/docs/index.rst
@@ -0,0 +1,20 @@
+.. Stem documentation master file, created by
+ sphinx-quickstart on Thu May 31 09:56:13 2012.
+ You can adapt this file completely to your liking, but it should at least
+ contain the root `toctree` directive.
+
+Welcome to Stem's documentation!
+================================
+
+Contents:
+
+.. toctree::
+ :maxdepth: 2
+
+Indices and tables
+==================
+
+* :ref:`genindex`
+* :ref:`modindex`
+* :ref:`search`
+
diff --git a/docs/make.bat b/docs/make.bat
new file mode 100644
index 0000000..22e89e2
--- /dev/null
+++ b/docs/make.bat
@@ -0,0 +1,155 @@
+@ECHO OFF
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set BUILDDIR=_build
+set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
+if NOT "%PAPER%" == "" (
+ set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
+)
+
+if "%1" == "" goto help
+
+if "%1" == "help" (
+ :help
+ echo.Please use `make ^<target^>` where ^<target^> is one of
+ echo. html to make standalone HTML files
+ echo. dirhtml to make HTML files named index.html in directories
+ echo. singlehtml to make a single large HTML file
+ echo. pickle to make pickle files
+ echo. json to make JSON files
+ echo. htmlhelp to make HTML files and a HTML help project
+ echo. qthelp to make HTML files and a qthelp project
+ echo. devhelp to make HTML files and a Devhelp project
+ echo. epub to make an epub
+ echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
+ echo. text to make text files
+ echo. man to make manual pages
+ echo. changes to make an overview over all changed/added/deprecated items
+ echo. linkcheck to check all external links for integrity
+ echo. doctest to run all doctests embedded in the documentation if enabled
+ goto end
+)
+
+if "%1" == "clean" (
+ for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
+ del /q /s %BUILDDIR%\*
+ goto end
+)
+
+if "%1" == "html" (
+ %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/html.
+ goto end
+)
+
+if "%1" == "dirhtml" (
+ %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
+ goto end
+)
+
+if "%1" == "singlehtml" (
+ %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
+ echo.
+ echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
+ goto end
+)
+
+if "%1" == "pickle" (
+ %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
+ echo.
+ echo.Build finished; now you can process the pickle files.
+ goto end
+)
+
+if "%1" == "json" (
+ %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
+ echo.
+ echo.Build finished; now you can process the JSON files.
+ goto end
+)
+
+if "%1" == "htmlhelp" (
+ %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
+ echo.
+ echo.Build finished; now you can run HTML Help Workshop with the ^
+.hhp project file in %BUILDDIR%/htmlhelp.
+ goto end
+)
+
+if "%1" == "qthelp" (
+ %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
+ echo.
+ echo.Build finished; now you can run "qcollectiongenerator" with the ^
+.qhcp project file in %BUILDDIR%/qthelp, like this:
+ echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Stem.qhcp
+ echo.To view the help file:
+ echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Stem.ghc
+ goto end
+)
+
+if "%1" == "devhelp" (
+ %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
+ echo.
+ echo.Build finished.
+ goto end
+)
+
+if "%1" == "epub" (
+ %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
+ echo.
+ echo.Build finished. The epub file is in %BUILDDIR%/epub.
+ goto end
+)
+
+if "%1" == "latex" (
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
+ echo.
+ echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
+ goto end
+)
+
+if "%1" == "text" (
+ %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
+ echo.
+ echo.Build finished. The text files are in %BUILDDIR%/text.
+ goto end
+)
+
+if "%1" == "man" (
+ %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
+ echo.
+ echo.Build finished. The manual pages are in %BUILDDIR%/man.
+ goto end
+)
+
+if "%1" == "changes" (
+ %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
+ echo.
+ echo.The overview file is in %BUILDDIR%/changes.
+ goto end
+)
+
+if "%1" == "linkcheck" (
+ %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
+ echo.
+ echo.Link check complete; look for any errors in the above output ^
+or in %BUILDDIR%/linkcheck/output.txt.
+ goto end
+)
+
+if "%1" == "doctest" (
+ %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
+ echo.
+ echo.Testing of doctests in the sources finished, look at the ^
+results in %BUILDDIR%/doctest/output.txt.
+ goto end
+)
+
+:end
1
0
commit 438dc79a512879473499211988a86e08099720de
Author: Damian Johnson <atagar(a)torproject.org>
Date: Sun Jun 3 16:21:26 2012 -0700
Missed linking a funcion
---
stem/process.py | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/stem/process.py b/stem/process.py
index 0224e3e..5df04dc 100644
--- a/stem/process.py
+++ b/stem/process.py
@@ -111,9 +111,9 @@ def launch_tor(tor_cmd = "tor", args = None, torrc_path = None, completion_perce
def launch_tor_with_config(config, tor_cmd = "tor", completion_percent = 100, init_msg_handler = None, timeout = DEFAULT_INIT_TIMEOUT):
"""
- Initializes a tor process, like launch_tor(), but with a customized
- configuration. This writes a temporary torrc to disk, launches tor, then
- deletes the torrc.
+ Initializes a tor process, like :func:`stem.process.launch_tor`, but with a
+ customized configuration. This writes a temporary torrc to disk, launches
+ tor, then deletes the torrc.
:param dict config: configuration options, such as ``{"ControlPort": "9051"}``
:param str tor_cmd: command for starting tor
1
0

06 Jun '12
commit 5c9579626a131e8bd17c283e0904525e30fe4488
Author: Damian Johnson <atagar(a)torproject.org>
Date: Sat Jun 2 11:06:42 2012 -0700
Adding module metadata (author, version, etc)
---
stem/__init__.py | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/stem/__init__.py b/stem/__init__.py
index 30e4f81..152a7df 100644
--- a/stem/__init__.py
+++ b/stem/__init__.py
@@ -2,5 +2,13 @@
Library for working with the tor process.
"""
+__version__ = '0.0.1'
+__author__ = 'Damian Johnson'
+__contact__ = 'atagar(a)torproject.org'
+__url__ = 'http://www.atagar.com/stem/'
+__license__ = 'LGPLv3'
+
__all__ = ["descriptor", "response", "util", "connection", "control", "process", "socket", "version"]
+
+
1
0

06 Jun '12
commit c03ebb23ae39f9c9b68a1471dbf3debb30c399a7
Author: Damian Johnson <atagar(a)torproject.org>
Date: Sun Jun 3 21:26:21 2012 -0700
Defaulting connect_* to provide a Controller
As a TODO comment mentioned, the connect_* convenience functions were supposed
to provide a higher level controller class when one was available. It now does.
---
stem/connection.py | 7 +++----
1 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/stem/connection.py b/stem/connection.py
index 99bc623..3f971bf 100644
--- a/stem/connection.py
+++ b/stem/connection.py
@@ -72,13 +72,14 @@ import binascii
import stem.response
import stem.socket
+import stem.control
import stem.version
import stem.util.enum
import stem.util.system
import stem.util.log as log
from stem.response.protocolinfo import AuthMethod
-def connect_port(control_addr = "127.0.0.1", control_port = 9051, password = None, chroot_path = None, controller = None):
+def connect_port(control_addr = "127.0.0.1", control_port = 9051, password = None, chroot_path = None, controller = stem.control.Controller):
"""
Convenience function for quickly getting a control connection. This is very
handy for debugging or CLI setup, handling setup and prompting for a password
@@ -94,8 +95,6 @@ def connect_port(control_addr = "127.0.0.1", control_port = 9051, password = Non
:returns: authenticated control connection, the type based on the controller argument
"""
- # TODO: replace the controller arg's default when we have something better
-
try:
control_port = stem.socket.ControlPort(control_addr, control_port)
except stem.socket.SocketError, exc:
@@ -104,7 +103,7 @@ def connect_port(control_addr = "127.0.0.1", control_port = 9051, password = Non
return _connect(control_port, password, chroot_path, controller)
-def connect_socket_file(socket_path = "/var/run/tor/control", password = None, chroot_path = None, controller = None):
+def connect_socket_file(socket_path = "/var/run/tor/control", password = None, chroot_path = None, controller = stem.control.Controller):
"""
Convenience function for quickly getting a control connection. For more
information see the connect_port function.
1
0
commit 1ccf6be7dec076afdf4c4a4150c38b5065a8f17e
Author: Damian Johnson <atagar(a)torproject.org>
Date: Sun Jun 3 16:28:07 2012 -0700
Switching to the haiku theme
The haiku theme is lighter, and lacks a left-hand bar which makes the content
far less cramped. All in all, looks far nicer for the content that we have so
far.
---
docs/conf.py | 4 ++--
1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/docs/conf.py b/docs/conf.py
index a9d4b7d..ada61ec 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -97,8 +97,8 @@ pygments_style = 'sphinx'
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
-html_theme = 'default'
-#html_theme = 'haiku'
+#html_theme = 'default'
+html_theme = 'haiku'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
1
0
commit 1cfad693de89bc4769605f21d52ef9ba4f38205b
Author: Damian Johnson <atagar(a)torproject.org>
Date: Mon Jun 4 10:04:45 2012 -0700
Adding module overviews back to docs
One bit of documentation that I've found very useful, and sphinx lacks, is a
brief summary of a module's contents. Hence adding that back to the headers.
---
stem/connection.py | 14 +++++++++++++-
stem/process.py | 7 +++++++
stem/version.py | 33 ++++++++++++++++++++-------------
3 files changed, 40 insertions(+), 14 deletions(-)
diff --git a/stem/connection.py b/stem/connection.py
index 3f971bf..ce83068 100644
--- a/stem/connection.py
+++ b/stem/connection.py
@@ -41,8 +41,20 @@ the authentication process. For instance...
print "Unable to authenticate: %s" % exc
sys.exit(1)
-Authentication failure exception hierchy::
+**Module Overview:**
+::
+
+ connect_port - Convenience method to get an authenticated control connection.
+ connect_socket_file - Similar to connect_port, but for control socket files.
+
+ authenticate - Main method for authenticating to a control socket.
+ authenticate_none - Authenticates to an open control socket.
+ authenticate_password - Authenticates to a socket supporting password auth.
+ authenticate_cookie - Authenticates to a socket supporting cookie auth.
+
+ get_protocolinfo - Issues a PROTOCOLINFO query.
+
AuthenticationFailure - Base exception raised for authentication failures.
|- UnrecognizedAuthMethods - Authentication methods are unsupported.
|- IncorrectSocketType - Socket does not speak the tor control protocol.
diff --git a/stem/process.py b/stem/process.py
index 5df04dc..b0e5015 100644
--- a/stem/process.py
+++ b/stem/process.py
@@ -6,6 +6,13 @@ Helper functions for working with tor as a process.
:DEFAULT_INIT_TIMEOUT:
number of seconds before we time out our attempt to start a tor instance
+
+**Module Overview:**
+
+::
+
+ launch_tor - starts up a tor process
+ launch_tor_with_config - starts a tor process with a custom torrc
"""
import re
diff --git a/stem/version.py b/stem/version.py
index 925acf0..0159512 100644
--- a/stem/version.py
+++ b/stem/version.py
@@ -2,19 +2,26 @@
Tor versioning information and requirements for its features. These can be
easily parsed and compared, for instance...
->>> my_version = stem.version.get_system_tor_version()
->>> print my_version
-0.2.1.30
->>> my_version > stem.version.Requirement.CONTROL_SOCKET
-True
+::
-+----------------------------------------------------------+
-|Requirement |
-+=====================+====================================+
-|GETINFO_CONFIG_TEXT |'GETINFO config-text' query |
-+---------------------+------------------------------------+
-|CONTROL_SOCKET |'ControlSocket <path>' config option|
-+---------------------+------------------------------------+
+ >>> my_version = stem.version.get_system_tor_version()
+ >>> print my_version
+ 0.2.1.30
+ >>> my_version > stem.version.Requirement.CONTROL_SOCKET
+ True
+
+**Module Overview:**
+
+::
+
+ get_system_tor_version - gets the version of our system's tor installation
+ Version - Tor versioning information.
+ |- __str__ - string representation
+ +- __cmp__ - compares with another Version
+
+ Requirement - Enumerations for the version requirements of features.
+ |- GETINFO_CONFIG_TEXT - 'GETINFO config-text' query
+ +- CONTROL_SOCKET - 'ControlSocket <path>' config option
"""
import re
1
0

06 Jun '12
commit f46b5c7c0e543d90f26155e472a1658827c5f8fe
Author: Damian Johnson <atagar(a)torproject.org>
Date: Sun Jun 3 21:23:49 2012 -0700
Converting stem.connection to reStructuredText
---
docs/index.rst | 5 +
stem/connection.py | 456 +++++++++++++++++++++++++---------------------------
2 files changed, 225 insertions(+), 236 deletions(-)
diff --git a/docs/index.rst b/docs/index.rst
index c735bf6..04348da 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -8,6 +8,11 @@ Welcome to Stem!
Stem is a python controller library for `Tor <https://www.torproject.org/>`_. Like its predecessor, `TorCtl <https://www.torproject.org/getinvolved/volunteer.html.en#project-torctl>`_, it uses Tor's `control protocol <https://gitweb.torproject.org/torspec.git/blob/HEAD:/control-spec.txt>`_ to help developers program against the Tor process, enabling them to build things similar to `Vidalia <https://www.torproject.org/getinvolved/volunteer.html.en#project-vidalia>`_ and `arm <http://www.atagar.com/arm/>`_.
+:mod:`stem.connection`
+----------------------
+
+Connecting and authenticating to a Tor process.
+
:mod:`stem.process`
-------------------
diff --git a/stem/connection.py b/stem/connection.py
index c48a7b5..99bc623 100644
--- a/stem/connection.py
+++ b/stem/connection.py
@@ -10,6 +10,8 @@ undesirable for applications (uses stdin/stdout, suppresses exceptions, etc).
The 'authenticate' function, however, gives easy but fine-grained control over
the authentication process. For instance...
+::
+
import sys
import getpass
import stem.connection
@@ -39,37 +41,29 @@ the authentication process. For instance...
print "Unable to authenticate: %s" % exc
sys.exit(1)
-connect_port - Convenience method to get an authenticated control connection.
-connect_socket_file - Similar to connect_port, but for control socket files.
-
-authenticate - Main method for authenticating to a control socket.
-authenticate_none - Authenticates to an open control socket.
-authenticate_password - Authenticates to a socket supporting password auth.
-authenticate_cookie - Authenticates to a socket supporting cookie auth.
-
-get_protocolinfo - Issues a PROTOCOLINFO query.
-
-AuthenticationFailure - Base exception raised for authentication failures.
- |- UnrecognizedAuthMethods - Authentication methods are unsupported.
- |- IncorrectSocketType - Socket does not speak the tor control protocol.
- |
- |- OpenAuthFailed - Failure when authenticating by an open socket.
- | +- OpenAuthRejected - Tor rejected this method of authentication.
- |
- |- PasswordAuthFailed - Failure when authenticating by a password.
- | |- PasswordAuthRejected - Tor rejected this method of authentication.
- | |- IncorrectPassword - Password was rejected.
- | +- MissingPassword - Socket supports password auth but wasn't attempted.
- |
- |- CookieAuthFailed - Failure when authenticating by a cookie.
- | |- CookieAuthRejected - Tor rejected this method of authentication.
- | |- IncorrectCookieValue - Authentication cookie was rejected.
- | |- IncorrectCookieSize - Size of the cookie file is incorrect.
- | +- UnreadableCookieFile - Unable to read the contents of the auth cookie.
- |
- +- MissingAuthInfo - Unexpected PROTOCOLINFO response, missing auth info.
- |- NoAuthMethods - Missing any methods for authenticating.
- +- NoAuthCookie - Supports cookie auth but doesn't have its path.
+Authentication failure exception hierchy::
+
+ AuthenticationFailure - Base exception raised for authentication failures.
+ |- UnrecognizedAuthMethods - Authentication methods are unsupported.
+ |- IncorrectSocketType - Socket does not speak the tor control protocol.
+ |
+ |- OpenAuthFailed - Failure when authenticating by an open socket.
+ | +- OpenAuthRejected - Tor rejected this method of authentication.
+ |
+ |- PasswordAuthFailed - Failure when authenticating by a password.
+ | |- PasswordAuthRejected - Tor rejected this method of authentication.
+ | |- IncorrectPassword - Password was rejected.
+ | +- MissingPassword - Socket supports password auth but wasn't attempted.
+ |
+ |- CookieAuthFailed - Failure when authenticating by a cookie.
+ | |- CookieAuthRejected - Tor rejected this method of authentication.
+ | |- IncorrectCookieValue - Authentication cookie was rejected.
+ | |- IncorrectCookieSize - Size of the cookie file is incorrect.
+ | +- UnreadableCookieFile - Unable to read the contents of the auth cookie.
+ |
+ +- MissingAuthInfo - Unexpected PROTOCOLINFO response, missing auth info.
+ |- NoAuthMethods - Missing any methods for authenticating.
+ +- NoAuthCookie - Supports cookie auth but doesn't have its path.
"""
import os
@@ -84,92 +78,6 @@ import stem.util.system
import stem.util.log as log
from stem.response.protocolinfo import AuthMethod
-class AuthenticationFailure(Exception):
- """
- Base error for authentication failures.
-
- Attributes:
- auth_response (stem.socket.ControlMessage) - AUTHENTICATE response from
- the control socket, None if one wasn't received
- """
-
- def __init__(self, message, auth_response = None):
- Exception.__init__(self, message)
- self.auth_response = auth_response
-
-class UnrecognizedAuthMethods(AuthenticationFailure):
- "All methods for authenticating aren't recognized."
-
- def __init__(self, message, unknown_auth_methods):
- AuthenticationFailure.__init__(self, message)
- self.unknown_auth_methods = unknown_auth_methods
-
-class IncorrectSocketType(AuthenticationFailure):
- "Socket does not speak the control protocol."
-
-class OpenAuthFailed(AuthenticationFailure):
- "Failure to authenticate to an open socket."
-
-class OpenAuthRejected(OpenAuthFailed):
- "Attempt to connect to an open control socket was rejected."
-
-class PasswordAuthFailed(AuthenticationFailure):
- "Failure to authenticate with a password."
-
-class PasswordAuthRejected(PasswordAuthFailed):
- "Socket does not support password authentication."
-
-class IncorrectPassword(PasswordAuthFailed):
- "Authentication password incorrect."
-
-class MissingPassword(PasswordAuthFailed):
- "Password authentication is supported but we weren't provided with one."
-
-class CookieAuthFailed(AuthenticationFailure):
- "Failure to authenticate with an authentication cookie."
-
- def __init__(self, message, cookie_path, auth_response = None):
- AuthenticationFailure.__init__(self, message, auth_response)
- self.cookie_path = cookie_path
-
-class CookieAuthRejected(CookieAuthFailed):
- "Socket does not support password authentication."
-
-class IncorrectCookieValue(CookieAuthFailed):
- "Authentication cookie value was rejected."
-
-class IncorrectCookieSize(CookieAuthFailed):
- "Aborted because the cookie file is the wrong size."
-
-class UnreadableCookieFile(CookieAuthFailed):
- "Error arose in reading the authentication cookie."
-
-class MissingAuthInfo(AuthenticationFailure):
- """
- The PROTOCOLINFO response didn't have enough information to authenticate.
- These are valid control responses but really shouldn't happen in practice.
- """
-
-class NoAuthMethods(MissingAuthInfo):
- "PROTOCOLINFO response didn't have any methods for authenticating."
-
-class NoAuthCookie(MissingAuthInfo):
- "PROTOCOLINFO response supports cookie auth but doesn't have its path."
-
-# authentication exceptions ordered as per the authenticate function's pydocs
-AUTHENTICATE_EXCEPTIONS = (
- IncorrectSocketType,
- UnrecognizedAuthMethods,
- MissingPassword,
- IncorrectPassword,
- IncorrectCookieSize,
- UnreadableCookieFile,
- IncorrectCookieValue,
- OpenAuthRejected,
- MissingAuthInfo,
- AuthenticationFailure,
-)
-
def connect_port(control_addr = "127.0.0.1", control_port = 9051, password = None, chroot_path = None, controller = None):
"""
Convenience function for quickly getting a control connection. This is very
@@ -177,17 +85,13 @@ def connect_port(control_addr = "127.0.0.1", control_port = 9051, password = Non
if necessary (and none is provided). If any issues arise this prints a
description of the problem and returns None.
- Arguments:
- control_addr (str) - ip address of the controller
- control_port (int) - port number of the controller
- password (str) - passphrase to authenticate to the socket
- chroot_path (str) - path prefix if in a chroot environment
- controller (Class) - BaseController subclass to be returned, this provides
- a ControlSocket if None
-
- Returns:
- Authenticated control connection, the type based on the controller
- argument.
+ :param str control_addr: ip address of the controller
+ :param int control_port: port number of the controller
+ :param str password: passphrase to authenticate to the socket
+ :param str chroot_path: path prefix if in a chroot environment
+ :param Class controller: BaseController subclass to be returned, this provides a ControlSocket if None
+
+ :returns: authenticated control connection, the type based on the controller argument
"""
# TODO: replace the controller arg's default when we have something better
@@ -205,15 +109,12 @@ def connect_socket_file(socket_path = "/var/run/tor/control", password = None, c
Convenience function for quickly getting a control connection. For more
information see the connect_port function.
- Arguments:
- socket_path (str) - path where the control socket is located
- password (str) - passphrase to authenticate to the socket
- chroot_path (str) - path prefix if in a chroot environment
- controller (Class) - BaseController subclass to be returned, this provides
- a ControlSocket if None
+ :param str socket_path: path where the control socket is located
+ :param str password: passphrase to authenticate to the socket
+ :param str chroot_path: path prefix if in a chroot environment
+ :param Class controller: BaseController subclass to be returned, this provides a ControlSocket if None
- Returns:
- Authenticated control connection, the type based on the controller enum.
+ :returns: authenticated control connection, the type based on the controller argument
"""
try:
@@ -228,15 +129,12 @@ def _connect(control_socket, password, chroot_path, controller):
"""
Common implementation for the connect_* functions.
- Arguments:
- control_socket (stem.socket.ControlSocket) - socket being authenticated to
- password (str) - passphrase to authenticate to the socket
- chroot_path (str) - path prefix if in a chroot environment
- controller (Class) - BaseController subclass to be returned, this provides
- a ControlSocket if None
+ :param stem.socket.ControlSocket control_socket: socket being authenticated to
+ :param str password: passphrase to authenticate to the socket
+ :param str chroot_path: path prefix if in a chroot environment
+ :param Class controller: BaseController subclass to be returned, this provides a ControlSocket if None
- Returns:
- Authenticated control connection with a type based on the controller enum.
+ :returns: authenticated control connection, the type based on the controller argument
"""
try:
@@ -268,71 +166,76 @@ def authenticate(controller, password = None, chroot_path = None, protocolinfo_r
callers should catch the types of authentication failure that they care
about, then have a AuthenticationFailure catch-all at the end.
- Arguments:
- controller (stem.socket.ControlSocket or stem.control.BaseController) -
- tor controller connection to be authenticated
- password (str) - passphrase to present to the socket if it uses password
- authentication (skips password auth if None)
- chroot_path (str) - path prefix if in a chroot environment
- protocolinfo_response (stem.response.protocolinfo.ProtocolInfoResponse) -
- tor protocolinfo response, this is retrieved on our own if None
-
- Raises:
- AuthenticationFailed subclass if all attempts to authenticate fail. Since
- this may try multiple authentication methods it may encounter multiple
- exceptions. If so then the exception this raises is prioritized as
- follows...
-
- stem.connection.IncorrectSocketType
+ This can authenticate to either a :class:`stem.control.BaseController` or
+ :class:`stem.socket.ControlSocket`.
+
+ :param controller: tor controller or socket to be authenticated
+ :param str password: passphrase to present to the socket if it uses password authentication (skips password auth if None)
+ :param str chroot_path: path prefix if in a chroot environment
+ :param stem.response.protocolinfo.ProtocolInfoResponse protocolinfo_response: tor protocolinfo response, this is retrieved on our own if None
+
+ :raises: If all attempts to authenticate fails then this will raise a :class:`stem.connection.AuthenticationFailure` subclass. Since this may try multiple authentication methods it may encounter multiple exceptions. If so then the exception this raises is prioritized as follows...
+
+ * :class:`stem.connection.IncorrectSocketType`
+
The controller does not speak the tor control protocol. Most often this
happened because the user confused the SocksPort or ORPort with the
ControlPort.
- stem.connection.UnrecognizedAuthMethods
+ * :class:`stem.connection.UnrecognizedAuthMethods`
+
All of the authentication methods tor will accept are new and
unrecognized. Please upgrade stem and, if that doesn't work, file a
ticket on 'trac.torproject.org' and I'd be happy to add support.
- stem.connection.MissingPassword
+ * :class:`stem.connection.MissingPassword`
+
We were unable to authenticate but didn't attempt password authentication
because none was provided. You should prompt the user for a password and
try again via 'authenticate_password'.
- stem.connection.IncorrectPassword
+ * :class:`stem.connection.IncorrectPassword`
+
We were provided with a password but it was incorrect.
- stem.connection.IncorrectCookieSize
+ * :class:`stem.connection.IncorrectCookieSize`
+
Tor allows for authentication by reading it a cookie file, but that file
is the wrong size to be an authentication cookie.
- stem.connection.UnreadableCookieFile
+ * :class:`stem.connection.UnreadableCookieFile`
+
Tor allows for authentication by reading it a cookie file, but we can't
read that file (probably due to permissions).
- stem.connection.IncorrectCookieValue (*)
+ * **\***:class:`stem.connection.IncorrectCookieValue`
+
Tor allows for authentication by reading it a cookie file, but rejected
the contents of that file.
- stem.connection.OpenAuthRejected (*)
+ * **\***:class:`stem.connection.OpenAuthRejected`
+
Tor says that it allows for authentication without any credentials, but
then rejected our authentication attempt.
- stem.connection.MissingAuthInfo (*)
+ * **\***:class:`stem.connection.MissingAuthInfo`
+
Tor provided us with a PROTOCOLINFO reply that is technically valid, but
missing the information we need to authenticate.
- stem.connection.AuthenticationFailure (*)
+ * **\***:class:`stem.connection.AuthenticationFailure`
+
There are numerous other ways that authentication could have failed
including socket failures, malformed controller responses, etc. These
mostly constitute transient failures or bugs.
- * In practice it is highly unusual for this to occur, being more of a
- theoretical possibility rather than something you should expect. It's
- fine to treat these as errors. If you have a use case where this commonly
- happens, please file a ticket on 'trac.torproject.org'.
-
- In the future new AuthenticationFailure subclasses may be added to allow
- for better error handling.
+ **\*** In practice it is highly unusual for this to occur, being more of a
+ theoretical possibility rather than something you should expect. It's fine
+ to treat these as errors. If you have a use case where this commonly
+ happens, please file a ticket on 'trac.torproject.org'.
+
+ In the future new :class:`stem.connection.AuthenticationFailure` subclasses
+ may be added to allow for better error handling.
"""
if not protocolinfo_response:
@@ -431,17 +334,15 @@ def authenticate_none(controller, suppress_ctl_errors = True):
attempt to re-establish the connection. This may not succeed, so check
is_alive() before using the socket further.
- For general usage use the authenticate() function instead.
+ This can authenticate to either a :class:`stem.control.BaseController` or
+ :class:`stem.socket.ControlSocket`.
- Arguments:
- controller (stem.socket.ControlSocket or stem.control.BaseController) -
- tor controller connection
- suppress_ctl_errors (bool) - reports raised stem.socket.ControllerError as
- authentication rejection if True, otherwise they're re-raised
+ *For general usage use the authenticate() function instead.*
- Raises:
- stem.connection.OpenAuthRejected if the empty authentication credentials
- aren't accepted
+ :param controller: tor controller or socket to be authenticated
+ :param bool suppress_ctl_errors: reports raised :class:`stem.socket.ControllerError` as authentication rejection if True, otherwise they're re-raised
+
+ :raises: :class:`stem.connection.OpenAuthRejected` if the empty authentication credentials aren't accepted
"""
try:
@@ -469,26 +370,23 @@ def authenticate_password(controller, password, suppress_ctl_errors = True):
attempt to re-establish the connection. This may not succeed, so check
is_alive() before using the socket further.
- For general usage use the authenticate() function instead.
-
- note: If you use this function directly, rather than authenticate(), we may
+ If you use this function directly, rather than authenticate(), we may
mistakenly raise a PasswordAuthRejected rather than IncorrectPassword. This
is because we rely on tor's error messaging which is liable to change in
- future versions...
- https://trac.torproject.org/4817
-
- Arguments:
- controller (stem.socket.ControlSocket or stem.control.BaseController) -
- tor controller connection
- password (str) - passphrase to present to the socket
- suppress_ctl_errors (bool) - reports raised stem.socket.ControllerError as
- authentication rejection if True, otherwise they're re-raised
-
- Raises:
- stem.connection.PasswordAuthRejected if the socket doesn't accept password
- authentication
- stem.connection.IncorrectPassword if the authentication credentials aren't
- accepted
+ future versions (`ticket <https://trac.torproject.org/4817>`_).
+
+ This can authenticate to either a :class:`stem.control.BaseController` or
+ :class:`stem.socket.ControlSocket`.
+
+ *For general usage use the authenticate() function instead.*
+
+ :param controller: tor controller or socket to be authenticated
+ :param str password: passphrase to present to the socket
+ :param bool suppress_ctl_errors: reports raised :class:`stem.socket.ControllerError` as authentication rejection if True, otherwise they're re-raised
+
+ :raises:
+ * :class:`stem.connection.PasswordAuthRejected` if the socket doesn't accept password authentication
+ * :class:`stem.connection.IncorrectPassword` if the authentication credentials aren't accepted
"""
# Escapes quotes. Tor can include those in the password hash, in which case
@@ -534,28 +432,25 @@ def authenticate_cookie(controller, cookie_path, suppress_ctl_errors = True):
attempt to re-establish the connection. This may not succeed, so check
is_alive() before using the socket further.
- For general usage use the authenticate() function instead.
-
- note: If you use this function directly, rather than authenticate(), we may
+ If you use this function directly, rather than authenticate(), we may
mistakenly raise a CookieAuthRejected rather than IncorrectCookieValue. This
is because we rely on tor's error messaging which is liable to change in
- future versions...
- https://trac.torproject.org/4817
-
- Arguments:
- controller (stem.socket.ControlSocket or stem.control.BaseController) -
- tor controller connection
- cookie_path (str) - path of the authentication cookie to send to tor
- suppress_ctl_errors (bool) - reports raised stem.socket.ControllerError as
- authentication rejection if True, otherwise they're re-raised
-
- Raises:
- stem.connection.IncorrectCookieSize if the cookie file's size is wrong
- stem.connection.UnreadableCookieFile if the cookie file doesn't exist or
- we're unable to read it
- stem.connection.CookieAuthRejected if cookie authentication is attempted
- but the socket doesn't accept it
- stem.connection.IncorrectCookieValue if the cookie file's value is rejected
+ future versions (`ticket <https://trac.torproject.org/4817>`_).
+
+ This can authenticate to either a :class:`stem.control.BaseController` or
+ :class:`stem.socket.ControlSocket`.
+
+ *For general usage use the authenticate() function instead.*
+
+ :param controller: tor controller or socket to be authenticated
+ :param str cookie_path: path of the authentication cookie to send to tor
+ :param bool suppress_ctl_errors: reports raised :class:`stem.socket.ControllerError` as authentication rejection if True, otherwise they're re-raised
+
+ :raises:
+ * :class:`stem.connection.IncorrectCookieSize` if the cookie file's size is wrong
+ * :class:`stem.connection.UnreadableCookieFile` if the cookie file doesn't exist or we're unable to read it
+ * :class:`stem.connection.CookieAuthRejected` if cookie authentication is attempted but the socket doesn't accept it
+ * :class:`stem.connection.IncorrectCookieValue` if the cookie file's value is rejected
"""
if not os.path.exists(cookie_path):
@@ -615,23 +510,20 @@ def get_protocolinfo(controller):
first reconnected.
According to the control spec the cookie_file is an absolute path. However,
- this often is not the case (especially for the Tor Browser Bundle)...
- https://trac.torproject.org/projects/tor/ticket/1101
+ this often is not the case (especially for the Tor Browser Bundle). If the
+ path is relative then we'll make an attempt (which may not work) to correct
+ this (`ticket <https://trac.torproject.org/1101>`_).
- If the path is relative then we'll make an attempt (which may not work) to
- correct this.
+ This can authenticate to either a :class:`stem.control.BaseController` or
+ :class:`stem.socket.ControlSocket`.
- Arguments:
- controller (stem.socket.ControlSocket or stem.control.BaseController) -
- tor controller connection
+ :param controller: tor controller or socket to be queried
- Returns:
- stem.response.protocolinfo.ProtocolInfoResponse provided by tor
+ :returns: :class:`stem.response.protocolinfo.ProtocolInfoResponse` provided by tor
- Raises:
- stem.socket.ProtocolError if the PROTOCOLINFO response is malformed
- stem.socket.SocketError if problems arise in establishing or using the
- socket
+ :raises:
+ * :class:`stem.socket.ProtocolError` if the PROTOCOLINFO response is malformed
+ * :class:`stem.socket.SocketError` if problems arise in establishing or using the socket
"""
try:
@@ -714,3 +606,95 @@ def _expand_cookie_path(protocolinfo_response, pid_resolver, pid_resolution_arg)
protocolinfo_response.cookie_path = cookie_path
+class AuthenticationFailure(Exception):
+ """
+ Base error for authentication failures.
+
+ :var stem.socket.ControlMessage auth_response: AUTHENTICATE response from the control socket, None if one wasn't received
+ """
+
+ def __init__(self, message, auth_response = None):
+ Exception.__init__(self, message)
+ self.auth_response = auth_response
+
+class UnrecognizedAuthMethods(AuthenticationFailure):
+ """
+ All methods for authenticating aren't recognized.
+
+ :var list unknown_auth_methods: authentication methods that weren't recognized
+ """
+
+ def __init__(self, message, unknown_auth_methods):
+ AuthenticationFailure.__init__(self, message)
+ self.unknown_auth_methods = unknown_auth_methods
+
+class IncorrectSocketType(AuthenticationFailure):
+ "Socket does not speak the control protocol."
+
+class OpenAuthFailed(AuthenticationFailure):
+ "Failure to authenticate to an open socket."
+
+class OpenAuthRejected(OpenAuthFailed):
+ "Attempt to connect to an open control socket was rejected."
+
+class PasswordAuthFailed(AuthenticationFailure):
+ "Failure to authenticate with a password."
+
+class PasswordAuthRejected(PasswordAuthFailed):
+ "Socket does not support password authentication."
+
+class IncorrectPassword(PasswordAuthFailed):
+ "Authentication password incorrect."
+
+class MissingPassword(PasswordAuthFailed):
+ "Password authentication is supported but we weren't provided with one."
+
+class CookieAuthFailed(AuthenticationFailure):
+ """
+ Failure to authenticate with an authentication cookie.
+
+ :param str cookie_path: location of the authentication cookie we attempted
+ """
+
+ def __init__(self, message, cookie_path, auth_response = None):
+ AuthenticationFailure.__init__(self, message, auth_response)
+ self.cookie_path = cookie_path
+
+class CookieAuthRejected(CookieAuthFailed):
+ "Socket does not support password authentication."
+
+class IncorrectCookieValue(CookieAuthFailed):
+ "Authentication cookie value was rejected."
+
+class IncorrectCookieSize(CookieAuthFailed):
+ "Aborted because the cookie file is the wrong size."
+
+class UnreadableCookieFile(CookieAuthFailed):
+ "Error arose in reading the authentication cookie."
+
+class MissingAuthInfo(AuthenticationFailure):
+ """
+ The PROTOCOLINFO response didn't have enough information to authenticate.
+ These are valid control responses but really shouldn't happen in practice.
+ """
+
+class NoAuthMethods(MissingAuthInfo):
+ "PROTOCOLINFO response didn't have any methods for authenticating."
+
+class NoAuthCookie(MissingAuthInfo):
+ "PROTOCOLINFO response supports cookie auth but doesn't have its path."
+
+# authentication exceptions ordered as per the authenticate function's pydocs
+AUTHENTICATE_EXCEPTIONS = (
+ IncorrectSocketType,
+ UnrecognizedAuthMethods,
+ MissingPassword,
+ IncorrectPassword,
+ IncorrectCookieSize,
+ UnreadableCookieFile,
+ IncorrectCookieValue,
+ OpenAuthRejected,
+ MissingAuthInfo,
+ AuthenticationFailure,
+)
+
1
0

06 Jun '12
commit 68dc6af5c74cd8b733b07542c88f5af96bb146be
Author: Damian Johnson <atagar(a)torproject.org>
Date: Tue Jun 5 09:31:55 2012 -0700
Converting stem.response to reStructuredText
---
docs/index.rst | 7 +-
stem/response/__init__.py | 206 ++++++++++++++++++++---------------------
stem/response/getinfo.py | 3 +-
stem/response/protocolinfo.py | 50 ++++++----
4 files changed, 136 insertions(+), 130 deletions(-)
diff --git a/docs/index.rst b/docs/index.rst
index c3cd4d9..a5bc151 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -21,7 +21,7 @@ Provides the :class:`stem.control.Controller` class which, as the name implies,
:mod:`stem.socket`
------------------
-Base classes for communicating with a tor control socket.
+Base classes for communicating with a Tor control socket.
:mod:`stem.process`
-------------------
@@ -33,6 +33,11 @@ Used for launching Tor and managing the process.
Parsed versions that can be compared to the requirement for various features.
+:mod:`stem.response`
+--------------------
+
+Parsed replies that we receive from the Tor control socket.
+
.. toctree::
:maxdepth: 2
diff --git a/stem/response/__init__.py b/stem/response/__init__.py
index 1f2ed0c..823cefa 100644
--- a/stem/response/__init__.py
+++ b/stem/response/__init__.py
@@ -1,22 +1,26 @@
"""
Parses replies from the control socket.
-convert - translates a ControlMessage into a particular response subclass
+**Module Overview:**
-ControlMessage - Message that's read from the control socket.
- |- content - provides the parsed message content
- |- raw_content - unparsed socket data
- |- __str__ - content stripped of protocol formatting
- +- __iter__ - ControlLine entries for the content of the message
+::
-ControlLine - String subclass with methods for parsing controller responses.
- |- remainder - provides the unparsed content
- |- is_empty - checks if the remaining content is empty
- |- is_next_quoted - checks if the next entry is a quoted value
- |- is_next_mapping - checks if the next entry is a KEY=VALUE mapping
- |- peek_key - provides the key of the next entry
- |- pop - removes and returns the next entry
- +- pop_mapping - removes and returns the next entry as a KEY=VALUE mapping
+ convert - translates a ControlMessage into a particular response subclass
+
+ ControlMessage - Message that's read from the control socket.
+ |- content - provides the parsed message content
+ |- raw_content - unparsed socket data
+ |- __str__ - content stripped of protocol formatting
+ +- __iter__ - ControlLine entries for the content of the message
+
+ ControlLine - String subclass with methods for parsing controller responses.
+ |- remainder - provides the unparsed content
+ |- is_empty - checks if the remaining content is empty
+ |- is_next_quoted - checks if the next entry is a quoted value
+ |- is_next_mapping - checks if the next entry is a KEY=VALUE mapping
+ |- peek_key - provides the key of the next entry
+ |- pop - removes and returns the next entry
+ +- pop_mapping - removes and returns the next entry as a KEY=VALUE mapping
"""
__all__ = ["getinfo", "protocolinfo", "convert", "ControlMessage", "ControlLine"]
@@ -47,14 +51,12 @@ def convert(response_type, message):
If the response_type isn't recognized then this is leaves it alone.
- Arguments:
- response_type (str) - type of tor response to convert to
- message (stem.response.ControlMessage) - message to be converted
+ :param str response_type: type of tor response to convert to
+ :param stem.response.ControlMessage message: message to be converted
- Raises:
- stem.socket.ProtocolError the message isn't a proper response of that type
- TypeError if argument isn't a ControlMessage or response_type isn't
- supported
+ :raises:
+ * :class:`stem.socket.ProtocolError` the message isn't a proper response of that type
+ * TypeError if argument isn't a :class:`stem.response.ControlMessage` or response_type isn't supported
"""
import stem.response.getinfo
@@ -86,8 +88,7 @@ class ControlMessage:
"""
Checks if all of our lines have a 250 response.
- Returns:
- True if all lines have a 250 response code, False otherwise
+ :returns: True if all lines have a 250 response code, False otherwise
"""
for code, _, _ in self._parsed_content:
@@ -98,20 +99,26 @@ class ControlMessage:
def content(self):
"""
Provides the parsed message content. These are entries of the form...
- (status_code, divider, content)
- * status_code - Three character code for the type of response (defined in
- section 4 of the control-spec).
- * divider - Single character to indicate if this is mid-reply, data, or
- an end to the message (defined in section 2.3 of the
- control-spec).
- * content - The following content is the actual payload of the line.
+ ::
+
+ (status_code, divider, content)
+
+ **status_code**
+ Three character code for the type of response (defined in section 4 of
+ the control-spec).
+
+ **divider**
+ Single character to indicate if this is mid-reply, data, or an end to the
+ message (defined in section 2.3 of the control-spec).
+
+ **content**
+ The following content is the actual payload of the line.
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)
@@ -120,8 +127,7 @@ class ControlMessage:
"""
Provides the unparsed content read from the control socket.
- Returns:
- string of the socket data used to generate this message
+ :returns: string of the socket data used to generate this message
"""
return self._raw_content
@@ -139,17 +145,22 @@ class ControlMessage:
Provides ControlLine instances for the content of the message. This is
stripped of status codes and dividers, for instance...
- 250+info/names=
- desc/id/* -- Router descriptors by ID.
- desc/name/* -- Router descriptors by nickname.
- .
- 250 OK
+ ::
+
+ 250+info/names=
+ desc/id/* -- Router descriptors by ID.
+ desc/name/* -- Router descriptors by nickname.
+ .
+ 250 OK
Would provide two entries...
- 1st - "info/names=
- desc/id/* -- Router descriptors by ID.
- desc/name/* -- Router descriptors by nickname."
- 2nd - "OK"
+
+ ::
+
+ 1st - "info/names=
+ desc/id/* -- Router descriptors by ID.
+ desc/name/* -- Router descriptors by nickname."
+ 2nd - "OK"
"""
for _, _, content in self._parsed_content:
@@ -177,8 +188,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
@@ -187,8 +197,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 == ""
@@ -197,11 +206,9 @@ class ControlLine(str):
"""
Checks if our next entry is a quoted value or not.
- Arguments:
- escaped (bool) - 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)
@@ -211,15 +218,11 @@ class ControlLine(str):
"""
Checks if our next entry is a KEY=VALUE mapping or not.
- Arguments:
- key (str) - checks that the key matches this value, skipping the
- check if None
- quoted (bool) - checks that the mapping is to a quoted value
- escaped (bool) - unescapes the CONTROL_ESCAPES escape sequences
+ :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
- 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
@@ -243,8 +246,7 @@ class ControlLine(str):
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
@@ -260,29 +262,28 @@ class ControlLine(str):
Parses the next space separated entry, removing it and the space from our
remaining content. Examples...
- >>> line = ControlLine("\"We're all mad here.\" says the grinning cat.")
- >>> print line.pop(True)
- "We're all mad here."
- >>> print line.pop()
- "says"
- >>> print line.remainder()
- "the grinning cat."
-
- >>> line = ControlLine("\"this has a \\\" and \\\\ in it\" foo=bar more_data")
- >>> print line.pop(True, True)
- "this has a \" and \\ in it"
-
- Arguments:
- quoted (bool) - parses the next entry as a quoted value, removing the
- quotes
- escaped (bool) - unescapes the CONTROL_ESCAPES escape sequences
-
- 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
+ ::
+
+ >>> line = ControlLine("\\"We're all mad here.\\" says the grinning cat.")
+ >>> print line.pop(True)
+ "We're all mad here."
+ >>> print line.pop()
+ "says"
+ >>> print line.remainder()
+ "the grinning cat."
+
+ >>> line = ControlLine("\\"this has a \\\\\\" and \\\\\\\\ in it\\" foo=bar more_data")
+ >>> print line.pop(True, True)
+ "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
+
+ :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
"""
with self._remainder_lock:
@@ -295,16 +296,12 @@ class ControlLine(str):
Parses the next space separated entry as a KEY=VALUE mapping, removing it
and the space from our remaining content.
- Arguments:
- quoted (bool) - parses the value as being quoted, removing the quotes
- escaped (bool) - unescapes the CONTROL_ESCAPES escape sequences
+ :param bool quoted: parses the value as being quoted, removing the quotes
+ :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: ValueError if this isn't a KEY=VALUE mapping or if quoted is True without the value being quoted
"""
with self._remainder_lock:
@@ -326,18 +323,15 @@ def _parse_entry(line, quoted, escaped):
"""
Parses the next entry from the given space separated content.
- Arguments:
- line (str) - content to be parsed
- quoted (bool) - parses the next entry as a quoted value, removing the
- quotes
- escaped (bool) - unescapes the CONTROL_ESCAPES escape sequences
+ :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
- 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
+ :raises:
+ * ValueError if quoted is True without the next value being quoted
+ * IndexError if there's nothing to parse from the line
"""
if line == "":
@@ -368,12 +362,10 @@ def _get_quote_indeces(line, escaped):
"""
Provides the indices of the next two quotes in the given content.
- Arguments:
- line (str) - content to be parsed
- escaped (bool) - unescapes the CONTROL_ESCAPES escape sequences
+ :param str line: content to be parsed
+ :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
diff --git a/stem/response/getinfo.py b/stem/response/getinfo.py
index 6f6cde4..9b1fe75 100644
--- a/stem/response/getinfo.py
+++ b/stem/response/getinfo.py
@@ -5,8 +5,7 @@ class GetInfoResponse(stem.response.ControlMessage):
"""
Reply for a GETINFO query.
- Attributes:
- entries (dict) - mapping between the queried options and their values
+ :var dict entries: mapping between the queried options and their values
"""
def _parse_message(self):
diff --git a/stem/response/protocolinfo.py b/stem/response/protocolinfo.py
index ce9a82c..ece96a3 100644
--- a/stem/response/protocolinfo.py
+++ b/stem/response/protocolinfo.py
@@ -1,22 +1,32 @@
+"""
+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.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
-# 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.
-#
-# NONE - No authentication required
-# PASSWORD - See tor's HashedControlPassword option. Controllers must provide
-# the password used to generate the hash.
-# COOKIE - See tor's CookieAuthentication option. Controllers need to supply
-# the contents of the cookie file.
-# UNKNOWN - Tor provided one or more authentication methods that we don't
-# recognize. This is probably from a new addition to the control
-# protocol.
-
AuthMethod = stem.util.enum.Enum("NONE", "PASSWORD", "COOKIE", "UNKNOWN")
class ProtocolInfoResponse(stem.response.ControlMessage):
@@ -24,14 +34,14 @@ class ProtocolInfoResponse(stem.response.ControlMessage):
Version one PROTOCOLINFO query response.
The protocol_version is the only mandatory data for a valid PROTOCOLINFO
- response, so all other values are None if undefined or empty if a collection.
+ response, so all other values are ``None`` if undefined or empty if a
+ collection.
- Attributes:
- protocol_version (int) - protocol version of the response
- tor_version (stem.version.Version) - version of the tor process
- auth_methods (tuple) - AuthMethod types that tor will accept
- unknown_auth_methods (tuple) - strings of unrecognized auth methods
- cookie_path (str) - path of tor's authentication cookie
+ :var int protocol_version: protocol version of the response
+ :var stem.version.Version tor_version: version of the tor process
+ :var tuple auth_methods: AuthMethod types that tor will accept
+ :var tuple unknown_auth_methods: strings of unrecognized auth methods
+ :var str cookie_path: path of tor's authentication cookie
"""
def _parse_message(self):
1
0

[stem/master] Converting stem.util.connection to reStructuredText
by atagar@torproject.org 06 Jun '12
by atagar@torproject.org 06 Jun '12
06 Jun '12
commit c1392cd8b3322be4b39980dea54d5b224ed7062f
Author: Damian Johnson <atagar(a)torproject.org>
Date: Tue Jun 5 19:26:54 2012 -0700
Converting stem.util.connection to reStructuredText
---
stem/util/connection.py | 26 +++++++++-----------------
1 files changed, 9 insertions(+), 17 deletions(-)
diff --git a/stem/util/connection.py b/stem/util/connection.py
index 93030fc..cbf9856 100644
--- a/stem/util/connection.py
+++ b/stem/util/connection.py
@@ -1,8 +1,7 @@
"""
Connection and networking based utility functions. This will likely be expanded
-later to have all of arm's functions...
-https://gitweb.torproject.org/arm.git/blob/HEAD:/src/util/connections.py
-
+later to have all of `arm's functions
+<https://gitweb.torproject.org/arm.git/blob/HEAD:/src/util/connections.py>`_,
but for now just moving the parts we need.
"""
@@ -12,11 +11,9 @@ def is_valid_ip_address(address):
"""
Checks if a string is a valid IPv4 address.
- Arguments:
- address (str) - string to be checked
+ :param str address: string to be checked
- Returns:
- True if input is a valid IPv4 address, False otherwise.
+ :returns: True if input is a valid IPv4 address, False otherwise
"""
# checks if theres four period separated values
@@ -35,11 +32,9 @@ def is_valid_ipv6_address(address):
"""
Checks if a string is a valid IPv6 address.
- Arguments:
- address (str) - string to be checked
+ :param str address: string to be checked
- Returns:
- True if input is a valid IPv6 address, False otherwise.
+ :returns: True if input is a valid IPv6 address, False otherwise
"""
# addresses are made up of eight colon separated groups of four hex digits
@@ -65,13 +60,10 @@ def is_valid_port(entry, allow_zero = False):
"""
Checks if a string or int is a valid port number.
- Arguments:
- entry (str or int) - string or integer to be checked
- allow_zero (bool) - accept port number of zero (reserved by defintion)
+ :param str,int entry: string or integer to be checked
+ :param bool allow_zero: accept port number of zero (reserved by defintion)
- Returns:
- True if input is an integer and within the valid port range, False
- otherwise.
+ :returns: True if input is an integer and within the valid port range, False otherwise
"""
if isinstance(entry, str):
1
0

06 Jun '12
commit c350257b05455509ab99c9019747e63553a668d5
Author: Damian Johnson <atagar(a)torproject.org>
Date: Tue Jun 5 08:25:48 2012 -0700
Converting stem.socket to reStructuredText
---
docs/index.rst | 5 ++
stem/control.py | 2 +
stem/socket.py | 209 +++++++++++++++++++++++++------------------------------
3 files changed, 101 insertions(+), 115 deletions(-)
diff --git a/docs/index.rst b/docs/index.rst
index 2cf68fd..c3cd4d9 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -18,6 +18,11 @@ Connecting and authenticating to a Tor process.
Provides the :class:`stem.control.Controller` class which, as the name implies, is used for talking with and controlling a Tor instance. As a user this is the primary class that you'll need.
+:mod:`stem.socket`
+------------------
+
+Base classes for communicating with a tor control socket.
+
:mod:`stem.process`
-------------------
diff --git a/stem/control.py b/stem/control.py
index 7b56194..dbad4da 100644
--- a/stem/control.py
+++ b/stem/control.py
@@ -5,6 +5,8 @@ Controllers are a wrapper around a ControlSocket, retaining many of its methods
(connect, close, is_alive, etc) in addition to providing its own for
interacting at a higher level.
+**Module Overview:**
+
::
from_port - Provides a Controller based on a port connection.
diff --git a/stem/socket.py b/stem/socket.py
index 68cc7e4..2a9e737 100644
--- a/stem/socket.py
+++ b/stem/socket.py
@@ -1,31 +1,35 @@
"""
Supports message based communication with sockets speaking the tor control
protocol. This lets users send messages as basic strings and receive responses
-as instances of the ControlMessage class.
+as instances of the :class:`stem.response.ControlMessage` class.
-ControlSocket - Socket wrapper that speaks the tor control protocol.
- |- ControlPort - Control connection via a port.
- | |- get_address - provides the ip address of our socket
- | +- get_port - provides the port of our socket
- |
- |- ControlSocketFile - Control connection via a local file socket.
- | +- get_socket_path - provides the path of the socket we connect to
- |
- |- send - sends a message to the socket
- |- recv - receives a ControlMessage from the socket
- |- is_alive - reports if the socket is known to be closed
- |- connect - connects a new socket
- |- close - shuts down the socket
- +- __enter__ / __exit__ - manages socket connection
+**Module Overview:**
-send_message - Writes a message to a control socket.
-recv_message - Reads a ControlMessage from a control socket.
-send_formatting - Performs the formatting expected from sent messages.
+::
-ControllerError - Base exception raised when using the controller.
- |- ProtocolError - Malformed socket data.
- +- SocketError - Communication with the socket failed.
- +- SocketClosed - Socket has been shut down.
+ ControlSocket - Socket wrapper that speaks the tor control protocol.
+ |- ControlPort - Control connection via a port.
+ | |- get_address - provides the ip address of our socket
+ | +- get_port - provides the port of our socket
+ |
+ |- ControlSocketFile - Control connection via a local file socket.
+ | +- get_socket_path - provides the path of the socket we connect to
+ |
+ |- send - sends a message to the socket
+ |- recv - receives a ControlMessage from the socket
+ |- is_alive - reports if the socket is known to be closed
+ |- connect - connects a new socket
+ |- close - shuts down the socket
+ +- __enter__ / __exit__ - manages socket connection
+
+ send_message - Writes a message to a control socket.
+ recv_message - Reads a ControlMessage from a control socket.
+ send_formatting - Performs the formatting expected from sent messages.
+
+ ControllerError - Base exception raised when using the controller.
+ |- ProtocolError - Malformed socket data.
+ +- SocketError - Communication with the socket failed.
+ +- SocketClosed - Socket has been shut down.
"""
from __future__ import absolute_import
@@ -37,18 +41,6 @@ import stem.response
import stem.util.enum
import stem.util.log as log
-class ControllerError(Exception):
- "Base error for controller communication issues."
-
-class ProtocolError(ControllerError):
- "Malformed content from the control socket."
-
-class SocketError(ControllerError):
- "Error arose while communicating with the control socket."
-
-class SocketClosed(SocketError):
- "Control socket was closed before completing the message."
-
class ControlSocket:
"""
Wrapper for a socket connection that speaks the Tor control protocol. To the
@@ -56,7 +48,7 @@ class ControlSocket:
receiving complete messages. All methods are thread safe.
Callers should not instantiate this class directly, but rather use subclasses
- which are expected to implement the _make_socket method.
+ which are expected to implement the ``_make_socket()`` method.
"""
def __init__(self):
@@ -73,16 +65,14 @@ class ControlSocket:
def send(self, message, raw = False):
"""
Formats and sends a message to the control socket. For more information see
- the stem.socket.send_message function.
+ the :func:`stem.socket.send_message` function.
- Arguments:
- message (str) - message to be formatted and sent to the socket
- raw (bool) - leaves the message formatting untouched, passing it to
- the socket as-is
+ :param str message: message to be formatted and sent to the socket
+ :param bool raw: leaves the message formatting untouched, passing it to the socket as-is
- Raises:
- stem.socket.SocketError if a problem arises in using the socket
- stem.socket.SocketClosed if the socket is known to be shut down
+ :raises:
+ * :class:`stem.socket.SocketError` if a problem arises in using the socket
+ * :class:`stem.socket.SocketClosed` if the socket is known to be shut down
"""
with self._send_lock:
@@ -98,15 +88,13 @@ class ControlSocket:
def recv(self):
"""
Receives a message from the control socket, blocking until we've received
- one. For more information see the stem.socket.recv_message function.
+ one. For more information see the :func:`stem.socket.recv_message` function.
- Returns:
- stem.response.ControlMessage for the message received
+ :returns: :class:`stem.response.ControlMessage` for the message received
- Raises:
- stem.socket.ProtocolError the content from the socket is malformed
- stem.socket.SocketClosed if the socket closes before we receive a
- complete message
+ :raises:
+ * :class:`stem.socket.ProtocolError` the content from the socket is malformed
+ * :class:`stem.socket.SocketClosed` if the socket closes before we receive a complete message
"""
with self._recv_lock:
@@ -146,15 +134,14 @@ class ControlSocket:
until we either use it or have explicitily shut it down.
In practice a socket derived from a port knows about its disconnection
- after a failed recv() call. Socket file derived connections know after
- either a send() or recv().
+ after a failed ``recv()`` call. Socket file derived connections know after
+ either a ``send()`` or ``recv()``.
This means that to have reliable detection for when we're disconnected
you need to continually pull from the socket (which is part of what the
- BaseController does).
+ :class:`stem.control.BaseController` does).
- Returns:
- bool that's True if we're known to be shut down and False otherwise
+ :returns: bool that's True if we're known to be shut down and False otherwise
"""
return self._is_alive
@@ -164,8 +151,7 @@ class ControlSocket:
Connects to a new socket, closing our previous one if we're already
attached.
- Raises:
- stem.socket.SocketError if unable to make a socket
+ :raises: :class:`stem.socket.SocketError` if unable to make a socket
"""
with self._send_lock:
@@ -233,9 +219,7 @@ class ControlSocket:
because it's used to lock connect() / close(), and by extension our
is_alive() state changes.
- Returns:
- threading.RLock that governs sending messages to our socket and state
- changes
+ :returns: threading.RLock that governs sending messages to our socket and state changes
"""
return self._send_lock
@@ -264,12 +248,11 @@ class ControlSocket:
"""
Constructs and connects new socket. This is implemented by subclasses.
- Returns:
- socket.socket for our configuration
+ :returns: socket.socket for our configuration
- Raises:
- stem.socket.SocketError if unable to make a socket
- NotImplementedError if not implemented by a subclass
+ :raises:
+ * :class:`stem.socket.SocketError` if unable to make a socket
+ * NotImplementedError if not implemented by a subclass
"""
raise NotImplementedError("Unsupported Operation: this should be implemented by the ControlSocket subclass")
@@ -284,15 +267,11 @@ class ControlPort(ControlSocket):
"""
ControlPort constructor.
- Arguments:
- control_addr (str) - ip address of the controller
- control_port (int) - port number of the controller
- connect (bool) - connects to the socket if True, leaves it
- unconnected otherwise
+ :param str control_addr: ip address of the controller
+ :param int control_port: port number of the controller
+ :param bool connect: connects to the socket if True, leaves it unconnected otherwise
- Raises:
- stem.socket.SocketError if connect is True and we're unable to establish
- a connection
+ :raises: :class:`stem.socket.SocketError` if connect is True and we're unable to establish a connection
"""
ControlSocket.__init__(self)
@@ -305,8 +284,7 @@ class ControlPort(ControlSocket):
"""
Provides the ip address our socket connects to.
- Returns:
- str with the ip address of our socket
+ :returns: str with the ip address of our socket
"""
return self._control_addr
@@ -315,8 +293,7 @@ class ControlPort(ControlSocket):
"""
Provides the port our socket connects to.
- Returns:
- int with the port of our socket
+ :returns: int with the port of our socket
"""
return self._control_port
@@ -339,14 +316,10 @@ class ControlSocketFile(ControlSocket):
"""
ControlSocketFile constructor.
- Arguments:
- socket_path (str) - path where the control socket is located
- connect (bool) - connects to the socket if True, leaves it
- unconnected otherwise
+ :param str socket_path: path where the control socket is located
+ :param bool connect: connects to the socket if True, leaves it unconnected otherwise
- Raises:
- stem.socket.SocketError if connect is True and we're unable to establish
- a connection
+ :raises: :class:`stem.socket.SocketError` if connect is True and we're unable to establish a connection
"""
ControlSocket.__init__(self)
@@ -358,8 +331,7 @@ class ControlSocketFile(ControlSocket):
"""
Provides the path our socket connects to.
- Returns:
- str with the path for our control socket
+ :returns: str with the path for our control socket
"""
return self._socket_path
@@ -380,25 +352,26 @@ def send_message(control_file, message, raw = False):
line at the end). If the message doesn't contain a newline then it's sent
as...
- <message>\r\n
+ ::
+
+ <message>\\r\\n
+
+ and if it does contain newlines then it's split on ``\\n`` and sent as...
- and if it does contain newlines then it's split on \n and sent as...
+ ::
- +<line 1>\r\n
- <line 2>\r\n
- <line 3>\r\n
- .\r\n
+ +<line 1>\\r\\n
+ <line 2>\\r\\n
+ <line 3>\\r\\n
+ .\\r\\n
- Arguments:
- control_file (file) - file derived from the control socket (see the
- socket's makefile() method for more information)
- message (str) - message to be sent on the control socket
- raw (bool) - leaves the message formatting untouched, passing it
- to the socket as-is
+ :param file control_file: file derived from the control socket (see the socket's makefile() method for more information)
+ :param str message: message to be sent on the control socket
+ :param bool raw: leaves the message formatting untouched, passing it to the socket as-is
- Raises:
- stem.socket.SocketError if a problem arises in using the socket
- stem.socket.SocketClosed if the socket is known to be shut down
+ :raises:
+ * :class:`stem.socket.SocketError` if a problem arises in using the socket
+ * :class:`stem.socket.SocketClosed` if the socket is known to be shut down
"""
if not raw: message = send_formatting(message)
@@ -432,17 +405,13 @@ def recv_message(control_file):
Pulls from a control socket until we either have a complete message or
encounter a problem.
- Arguments:
- control_file (file) - file derived from the control socket (see the
- socket's makefile() method for more information)
+ :param file control_file: file derived from the control socket (see the socket's makefile() method for more information)
- Returns:
- stem.response.ControlMessage read from the socket
+ :returns: :class:`stem.response.ControlMessage` read from the socket
- Raises:
- stem.socket.ProtocolError the content from the socket is malformed
- stem.socket.SocketClosed if the socket closes before we receive a complete
- message
+ :raises:
+ * :class:`stem.socket.ProtocolError` the content from the socket is malformed
+ * :class:`stem.socket.SocketClosed` if the socket closes before we receive a complete message
"""
parsed_content, raw_content = [], ""
@@ -547,13 +516,11 @@ def recv_message(control_file):
def send_formatting(message):
"""
Performs the formatting expected from sent control messages. For more
- information see the stem.socket.send_message function.
+ information see the :func:`stem.socket.send_message` function.
- Arguments:
- message (str) - message to be formatted
+ :param str message: message to be formatted
- Returns:
- str of the message wrapped by the formatting expected from controllers
+ :returns: str of the message wrapped by the formatting expected from controllers
"""
# From control-spec section 2.2...
@@ -573,3 +540,15 @@ def send_formatting(message):
else:
return message + "\r\n"
+class ControllerError(Exception):
+ "Base error for controller communication issues."
+
+class ProtocolError(ControllerError):
+ "Malformed content from the control socket."
+
+class SocketError(ControllerError):
+ "Error arose while communicating with the control socket."
+
+class SocketClosed(SocketError):
+ "Control socket was closed before completing the message."
+
1
0