diff --git a/kgb/agency.py b/kgb/agency.py
index edd4fe14ec0509f10ed8cc9ff22d979ac0ab9a8e..8e1791054d960be120bf112f9e75f2fddb2ef1de 100644
--- a/kgb/agency.py
+++ b/kgb/agency.py
@@ -1,3 +1,5 @@
+"""A spy agency to manage spies."""
+
 from __future__ import unicode_literals
 
 from kgb.spies import FunctionSpy
@@ -6,19 +8,35 @@ from kgb.spies import FunctionSpy
 class SpyAgency(object):
     """Manages spies.
 
-    A SpyAgency can be instantiated or mixed into a TestCase in order
-    to provide spies.
+    A SpyAgency can be instantiated or mixed into a
+    :py:class:`unittest.TestCase` in order to provide spies.
 
     Every spy created through this agency will be tracked, and can be later
     be removed (individually or at once).
+
+    Attributes:
+        spies (set of kgb.spies.FunctionSpy):
+            All spies currently registered with this agency.
     """
+
     def __init__(self, *args, **kwargs):
+        """Initialize the spy agency.
+
+        Args:
+            *args (tuple):
+                Positional arguments to pass on to any other class (if using
+                this as a mixin).
+
+            **kwargs (dict):
+                Keyword arguments to pass on to any other class (if using
+                this as a mixin).
+        """
         super(SpyAgency, self).__init__(*args, **kwargs)
 
         self.spies = set()
 
     def tearDown(self):
-        """Tears down a test suite.
+        """Tear down a test suite.
 
         This is used when SpyAgency is mixed into a TestCase. It will
         automatically remove all spies when tearing down.
@@ -27,25 +45,47 @@ class SpyAgency(object):
         self.unspy_all()
 
     def spy_on(self, *args, **kwargs):
-        """Spies on a function.
+        """Spy on a function.
 
         By default, the spy will allow the call to go through to the original
-        function. This can be disabled by passing call_original=False when
+        function. This can be disabled by passing ``call_original=False`` when
         initiating the spy. If disabled, the original function will never be
         called.
 
-        This can also be passed a call_fake parameter pointing to another
+        This can also be passed a ``call_fake`` parameter pointing to another
         function to call instead of the original. If passed, this will take
-        precedence over call_original.
+        precedence over ``call_original``.
 
-        The FunctionSpy for this spy is returned.
+        See :py:class:`~kgb.spies.FunctionSpy` for more details on arguments.
+
+        Args:
+            *args (tuple):
+                Positional arguments to pass to
+                :py:class:`~kgb.spies.FunctionSpy`.
+
+            **kwargs (dict):
+                Keyword arguments to pass to
+                :py:class:`~kgb.spies.FunctionSpy`.
+
+        Returns:
+            kgb.spies.FunctionSpy:
+            The resulting spy.
         """
         spy = FunctionSpy(self, *args, **kwargs)
         self.spies.add(spy)
         return spy
 
     def unspy(self, func):
-        """Stops spying on a function."""
+        """Stop spying on a function.
+
+        Args:
+            func (callable):
+                The function to stop spying on.
+
+        Raises:
+            ValueError:
+                The provided function was not spied on.
+        """
         try:
             spy = func.spy
         except AttributeError:
@@ -56,7 +96,7 @@ class SpyAgency(object):
         spy.unspy()
 
     def unspy_all(self):
-        """Stops spying on all functions tracked by this agency."""
+        """Stop spying on all functions tracked by this agency."""
         for spy in self.spies:
             spy.unspy(unregister=False)
 
diff --git a/kgb/contextmanagers.py b/kgb/contextmanagers.py
index 2f8cb229b7dbef3f5e9409fef41ec93b14abb298..ad4c10de24a14087945e9ec2c7a913930bb8ffe4 100644
--- a/kgb/contextmanagers.py
+++ b/kgb/contextmanagers.py
@@ -1,3 +1,5 @@
+"""Standalone context managers for working with spies."""
+
 from __future__ import unicode_literals
 
 from contextlib import contextmanager
@@ -7,22 +9,38 @@ from kgb.agency import SpyAgency
 
 @contextmanager
 def spy_on(*args, **kwargs):
-    """Spies on a function.
+    """Spy on a function.
 
     By default, the spy will allow the call to go through to the original
-    function. This can be disabled by passing call_original=False when
+    function. This can be disabled by passing ``call_original=False`` when
     initiating the spy. If disabled, the original function will never be
     called.
 
-    This can also be passed a call_fake parameter pointing to another
+    This can also be passed a ``call_fake`` parameter pointing to another
     function to call instead of the original. If passed, this will take
-    precedence over call_original.
+    precedence over ``call_original``.
 
     The spy will only remain throughout the duration of the context.
+
+    See :py:class:`~kgb.spies.FunctionSpy` for more details on arguments.
+
+    Args:
+        *args (tuple):
+            Positional arguments to pass to
+            :py:class:`~kgb.spies.FunctionSpy`.
+
+        **kwargs (dict):
+            Keyword arguments to pass to
+            :py:class:`~kgb.spies.FunctionSpy`.
+
+    Context:
+        kgb.spies.FunctionSpy:
+        The newly-created spy.
     """
     agency = SpyAgency()
     spy = agency.spy_on(*args, **kwargs)
 
-    yield spy
-
-    spy.unspy()
+    try:
+        yield spy
+    finally:
+        spy.unspy()
diff --git a/kgb/errors.py b/kgb/errors.py
index 041a61f202d4c0fcf5f28b03d8f02b4f9f300a83..bccc810b30843b3c044d9f230666291407c81b1f 100644
--- a/kgb/errors.py
+++ b/kgb/errors.py
@@ -1,3 +1,5 @@
+"""Spy-related errors."""
+
 from __future__ import unicode_literals
 
 import traceback
