diff --git a/lib/spack/llnl/util/link_tree.py b/lib/spack/llnl/util/link_tree.py
index 887f6f4d26ae3869e5b07482c322362fcd70f252..4e4e48316e86435659d5ed537d089b5a4fc5131c 100644
--- a/lib/spack/llnl/util/link_tree.py
+++ b/lib/spack/llnl/util/link_tree.py
@@ -27,7 +27,7 @@
 
 import os
 import shutil
-from llnl.util.filesystem import mkdirp
+from llnl.util.filesystem import *
 
 empty_file_name = '.spack-empty'
 
@@ -93,6 +93,7 @@ def traverse_tree(source_root, dest_root, rel_path='', **kwargs):
     for f in os.listdir(source_path):
         source_child = os.path.join(source_path, f)
         dest_child   = os.path.join(dest_path, f)
+        rel_child    = os.path.join(rel_path, f)
 
         # Treat as a directory
         if os.path.isdir(source_child) and (
@@ -101,7 +102,7 @@ def traverse_tree(source_root, dest_root, rel_path='', **kwargs):
             # When follow_nonexisting isn't set, don't descend into dirs
             # in source that do not exist in dest
             if follow_nonexisting or os.path.exists(dest_child):
-                tuples = traverse_tree(source_child, dest_child, rel_path, **kwargs)
+                tuples = traverse_tree(source_root, dest_root, rel_child, **kwargs)
                 for t in tuples: yield t
 
         # Treat as a file.
diff --git a/lib/spack/spack/cmd/extensions.py b/lib/spack/spack/cmd/extensions.py
index 961d7e3f24898d65c393727355b7308e22dbd82d..f28a388bf2a00cb93a14c7112f52b139d9bc4c7d 100644
--- a/lib/spack/spack/cmd/extensions.py
+++ b/lib/spack/spack/cmd/extensions.py
@@ -26,6 +26,7 @@
 from external import argparse
 
 import llnl.util.tty as tty
+from llnl.util.tty.colify import colify
 
 import spack
 import spack.cmd
@@ -66,10 +67,10 @@ def extensions(parser, args):
 
     exts = spack.install_layout.get_extensions(spec)
     if not exts:
-        tty.msg("%s has no activated extensions." % spec.short_spec)
+        tty.msg("%s has no activated extensions." % spec.cshort_spec)
     else:
-        tty.msg("Showing %d activated extension%s for package:"
-                % (len(exts), 's' if len(exts) > 1 else ''),
-                spec.short_spec)
+        tty.msg("Extensions for package %s:" % spec.cshort_spec)
+        colify(pkg.name for pkg in spack.db.extensions_for(spec))
         print
+        tty.msg("%d currently activated:" % len(exts))
         spack.cmd.find.display_specs(exts, mode=args.mode)
diff --git a/lib/spack/spack/directory_layout.py b/lib/spack/spack/directory_layout.py
index ff327ed504720184ccb131c0b64f13df7a5a5477..efc40a17a4f07ea7ab2ac3d03b2fabaf4e832716 100644
--- a/lib/spack/spack/directory_layout.py
+++ b/lib/spack/spack/directory_layout.py
@@ -269,8 +269,8 @@ def extension_file_path(self, spec):
     def get_extensions(self, spec):
         _check_concrete(spec)
 
-        path = self.extension_file_path(spec)
         extensions = set()
+        path = self.extension_file_path(spec)
         if os.path.exists(path):
             with closing(open(path)) as ext_file:
                 for line in ext_file:
diff --git a/lib/spack/spack/package.py b/lib/spack/spack/package.py
index 0b6bc4ce6cd8a2181b66809034ddf3fd43872013..b90596854054e41e8c8ffca3438916f4f7350a42 100644
--- a/lib/spack/spack/package.py
+++ b/lib/spack/spack/package.py
@@ -522,6 +522,11 @@ def is_extension(self):
         return len(self.extendees) > 0
 
 
+    def extends(self, spec):
+        return (spec.name in self.extendees and
+                spec.satisfies(self.extendees[spec.name][0]))
+
+
     @property
     def activated(self):
         if not self.spec.concrete:
diff --git a/lib/spack/spack/packages.py b/lib/spack/spack/packages.py
index bb5a94bcab95ad1715ddd745026de2cb8866de9c..b3049e812f0304b60968d6d4de91b5daba2fbfa6 100644
--- a/lib/spack/spack/packages.py
+++ b/lib/spack/spack/packages.py
@@ -112,6 +112,11 @@ def providers_for(self, vpkg_spec):
         return providers
 
 
+    @_autospec
+    def extensions_for(self, extendee_spec):
+        return [p for p in self.all_packages() if p.extends(extendee_spec)]
+
+
     def dirname_for_package_name(self, pkg_name):
         """Get the directory name for a particular package.  This is the
            directory that contains its package.py file."""
diff --git a/lib/spack/spack/spec.py b/lib/spack/spack/spec.py
index 2f4fe9ca24d93b1c2c07ab5c2d0e1627f3f06860..dffdccaddb948434a6a58693781c9b7f47bbc3b3 100644
--- a/lib/spack/spack/spec.py
+++ b/lib/spack/spack/spec.py
@@ -552,6 +552,13 @@ def short_spec(self):
         return self.format('$_$@$%@$+$=$#')
 
 
+    @property
+    def cshort_spec(self):
+        """Returns a version of the spec with the dependencies hashed
+           instead of completely enumerated."""
+        return self.format('$_$@$%@$+$=$#', color=True)
+
+
     @property
     def prefix(self):
         return Prefix(spack.install_layout.path_for_spec(self))
diff --git a/var/spack/packages/py-basemap/package.py b/var/spack/packages/py-basemap/package.py
index 8955bf8827f3e7d6924d0446b923d9cdeff3064c..7b6d8e7e657d943a0bb41dee8c7f369c9c8c64cd 100644
--- a/var/spack/packages/py-basemap/package.py
+++ b/var/spack/packages/py-basemap/package.py
@@ -11,6 +11,7 @@ class PyBasemap(Package):
     geos_version = {'1.0.7' : '3.3.3'}
 
     extends('python')
+    depends_on('py-setuptools')
     depends_on('py-numpy')
     depends_on('py-matplotlib')
     depends_on('py-pil')
diff --git a/var/spack/packages/python/package.py b/var/spack/packages/python/package.py
index a22bd54c82b5d2883aa4835e2d8fbcee1f70166c..8a6d574d9b26695ec27105527a6e2a73d026d765 100644
--- a/var/spack/packages/python/package.py
+++ b/var/spack/packages/python/package.py
@@ -1,6 +1,9 @@
 from spack import *
+import spack
 import os
 import re
+from contextlib import closing
+
 
 class Python(Package):
     """The Python programming language."""
@@ -29,6 +32,10 @@ def install(self, spec, prefix):
         make("install")
 
 
+    # ========================================================================
+    # Set up environment to make install easy for python extensions.
+    # ========================================================================
+
     @property
     def python_lib_dir(self):
         return os.path.join('lib', 'python%d.%d' % self.version[:2])
@@ -60,21 +67,81 @@ def setup_extension_environment(self, module, spec, ext_spec):
         mkdirp(module.site_packages_dir)
 
 
-    def make_ignore(self, args):
+    # ========================================================================
+    # Handle specifics of activating and deactivating python modules.
+    # ========================================================================
+
+    def python_ignore(self, ext_pkg, args):
         """Add some ignore files to activate/deactivate args."""
         orig_ignore = args.get('ignore', lambda f: False)
+
         def ignore(filename):
-            return (re.search(r'/site\.pyc?$', filename) or
-                    re.search(r'\.pth$', filename) or
+            # Always ignore easy-install.pth, as it needs to be merged.
+            patterns = [r'easy-install\.pth$']
+
+            # Ignore pieces of setuptools installed by other packages.
+            if ext_pkg.name != 'py-setuptools':
+                patterns.append(r'/site\.pyc?$')
+                patterns.append(r'setuptools\.pth')
+                patterns.append(r'bin/easy_install[^/]*$')
+                patterns.append(r'setuptools.*egg$')
+
+            return (any(re.search(p, filename) for p in patterns) or
                     orig_ignore(filename))
+
         return ignore
 
 
+    def write_easy_install_pth(self, extensions):
+        paths = []
+        for ext in extensions:
+            ext_site_packages = os.path.join(ext.prefix, self.site_packages_dir)
+            easy_pth = "%s/easy-install.pth" % ext_site_packages
+
+            if not os.path.isfile(easy_pth):
+                continue
+
+            with closing(open(easy_pth)) as f:
+                for line in f:
+                    line = line.rstrip()
+
+                    # Skip lines matching these criteria
+                    if not line: continue
+                    if re.search(r'^(import|#)', line): continue
+                    if (ext.name != 'py-setuptools' and
+                        re.search(r'setuptools.*egg$', line)): continue
+
+                    paths.append(line)
+
+        site_packages = os.path.join(self.prefix, self.site_packages_dir)
+        main_pth = "%s/easy-install.pth" % site_packages
+
+        if not paths:
+            if os.path.isfile(main_pth):
+                os.remove(main_pth)
+
+        else:
+            with closing(open(main_pth, 'w')) as f:
+                f.write("import sys; sys.__plen = len(sys.path)\n")
+                for path in paths:
+                    f.write("%s\n" % path)
+                f.write("import sys; new=sys.path[sys.__plen:]; del sys.path[sys.__plen:]; "
+                        "p=getattr(sys,'__egginsert',0); sys.path[p:p]=new; sys.__egginsert = p+len(new)\n")
+
+
     def activate(self, ext_pkg, **args):
-        args.update(ignore=self.make_ignore(args))
+        args.update(ignore=self.python_ignore(ext_pkg, args))
         super(Python, self).activate(ext_pkg, **args)
 
+        extensions = set(spack.install_layout.get_extensions(self.spec))
+        extensions.add(ext_pkg.spec)
+        self.write_easy_install_pth(extensions)
+
 
     def deactivate(self, ext_pkg, **args):
-        args.update(ignore=self.make_ignore(args))
+        args.update(ignore=self.python_ignore(ext_pkg, args))
         super(Python, self).deactivate(ext_pkg, **args)
+
+        extensions = set(spack.install_layout.get_extensions(self.spec))
+        extensions.remove(ext_pkg.spec)
+        self.write_easy_install_pth(extensions)