diff --git a/.travis.yml b/.travis.yml
index 5677901f66695ec1e7b6845836912e967493e5cb..0cc03d1029602e2089b82e86edef6982dec8d7f0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -29,7 +29,7 @@ env:
     - DISTRIB="ubuntu" PYTHON_VERSION="2.7" CYTHON_VERSION="0.23.4"
       COVERAGE=true
     # This environment tests the oldest supported anaconda env
-    - DISTRIB="conda" PYTHON_VERSION="2.6" INSTALL_MKL="false"
+    - DISTRIB="conda" PYTHON_VERSION="2.7" INSTALL_MKL="false"
       NUMPY_VERSION="1.6.2" SCIPY_VERSION="0.11.0" CYTHON_VERSION="0.23"
     # This environment tests the newest supported anaconda env
     # It also runs tests requiring Pandas.
diff --git a/README.rst b/README.rst
index 75ee8c7c1d64c0344b28693fe698d39af30a50e2..9996bab1110fdf067e91ccd34c0ef8da6ff9ac72 100644
--- a/README.rst
+++ b/README.rst
@@ -48,7 +48,7 @@ Dependencies
 
 scikit-learn requires:
 
-- Python (>= 2.6 or >= 3.3)
+- Python (>= 2.7 or >= 3.3)
 - NumPy (>= 1.6.1)
 - SciPy (>= 0.9)
 
diff --git a/build_tools/travis/install.sh b/build_tools/travis/install.sh
index def59e35f1d7c9a38be3c6aa1fd0f5861d12a0f8..acd72fbd3b4c1623f2f2c2e26d3dcc1668263ac0 100755
--- a/build_tools/travis/install.sh
+++ b/build_tools/travis/install.sh
@@ -53,23 +53,17 @@ if [[ "$DISTRIB" == "conda" ]]; then
     if [[ "$INSTALL_MKL" == "true" ]]; then
         conda create -n testenv --yes python=$PYTHON_VERSION pip nose \
             numpy=$NUMPY_VERSION scipy=$SCIPY_VERSION numpy scipy \
-            libgfortran mkl flake8 \
+            mkl flake8 cython=$CYTHON_VERSION \
             ${PANDAS_VERSION+pandas=$PANDAS_VERSION}
             
     else
         conda create -n testenv --yes python=$PYTHON_VERSION pip nose \
             numpy=$NUMPY_VERSION scipy=$SCIPY_VERSION \
-            libgfortran nomkl \
+            nomkl cython=$CYTHON_VERSION \
             ${PANDAS_VERSION+pandas=$PANDAS_VERSION}
     fi
     source activate testenv
 
-    # Temporary work around for Python 2.6 because cython >= 0.23 is
-    # required for building scikit-learn but python 2.6 and cython
-    # 0.23 are not compatible in conda. Remove the next line and
-    # install cython via conda when Python 2.6 support is removed.
-    pip install cython==$CYTHON_VERSION
-
     # Install nose-timer via pip
     pip install nose-timer
 
diff --git a/doc/developers/advanced_installation.rst b/doc/developers/advanced_installation.rst
index b4f6b482f9aa2eba536426c12063149f7170758a..5344cbaa9fb866dda0c1e23e10039621e0cca36c 100644
--- a/doc/developers/advanced_installation.rst
+++ b/doc/developers/advanced_installation.rst
@@ -35,7 +35,7 @@ Installing an official release
 
 Scikit-learn requires:
 
-- Python (>= 2.6 or >= 3.3),
+- Python (>= 2.7 or >= 3.3),
 - NumPy (>= 1.6.1),
 - SciPy (>= 0.9).
 
diff --git a/doc/developers/contributing.rst b/doc/developers/contributing.rst
index 4f406e50c6d63f69fb2b9c8a3c3a935fa3388356..c06773fae5f39dcfa1d735ba32f3a065a9b5c4bc 100644
--- a/doc/developers/contributing.rst
+++ b/doc/developers/contributing.rst
@@ -702,7 +702,7 @@ Python 3.x support
 All scikit-learn code should work unchanged in both Python 2.[67]
 and 3.2 or newer. Since Python 3.x is not backwards compatible,
 that may require changes to code and it certainly requires testing
-on both 2.6 or 2.7, and 3.2 or newer.
+on both 2.7 and 3.2 or newer.
 
 For most numerical algorithms, Python 3.x support is easy:
 just remember that ``print`` is a function and
diff --git a/doc/install.rst b/doc/install.rst
index 4ca21b9436d9d6dac826b3586bbbb509d9ac2584..78008cc6a6069ef964508d0f574f9bdcf27e26c4 100644
--- a/doc/install.rst
+++ b/doc/install.rst
@@ -15,7 +15,7 @@ Installing the latest release
 
 Scikit-learn requires:
 
-- Python (>= 2.6 or >= 3.3),
+- Python (>= 2.7 or >= 3.3),
 - NumPy (>= 1.6.1),
 - SciPy (>= 0.9).
 
diff --git a/setup.py b/setup.py
index 1a10d70f3ba5d0d2b097b0dafe5d43f4478e54b1..3817c8773fed48eb5df94a9e3d95da7193c948c0 100755
--- a/setup.py
+++ b/setup.py
@@ -200,7 +200,6 @@ def setup_package():
                                  'Operating System :: Unix',
                                  'Operating System :: MacOS',
                                  'Programming Language :: Python :: 2',
-                                 'Programming Language :: Python :: 2.6',
                                  'Programming Language :: Python :: 2.7',
                                  'Programming Language :: Python :: 3',
                                  'Programming Language :: Python :: 3.4',
diff --git a/sklearn/ensemble/tests/test_base.py b/sklearn/ensemble/tests/test_base.py
index bed9a3a5e81220aef2c011eaa722098e4f4369dd..6b81dbf67466da2554a2fa7e6f3e544c4a871a4f 100644
--- a/sklearn/ensemble/tests/test_base.py
+++ b/sklearn/ensemble/tests/test_base.py
@@ -16,7 +16,7 @@ from sklearn.datasets import load_iris
 from sklearn.ensemble import BaggingClassifier
 from sklearn.ensemble.base import _set_random_states
 from sklearn.linear_model import Perceptron
-from sklearn.externals.odict import OrderedDict
+from collections import OrderedDict
 from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
 from sklearn.pipeline import Pipeline
 from sklearn.feature_selection import SelectFromModel
diff --git a/sklearn/externals/funcsigs.py b/sklearn/externals/funcsigs.py
index 413e310a817109d59592fad1e8abc5b3c94e1369..4e684690b309c99921341aaa177d9d56f1d3c26a 100644
--- a/sklearn/externals/funcsigs.py
+++ b/sklearn/externals/funcsigs.py
@@ -2,7 +2,7 @@
 """Function signature objects for callables
 
 Back port of Python 3.3's function signature tools from the inspect module,
-modified to be compatible with Python 2.6, 2.7 and 3.2+.
+modified to be compatible with Python 2.7 and 3.2+.
 """
 from __future__ import absolute_import, division, print_function
 import itertools
@@ -10,10 +10,7 @@ import functools
 import re
 import types
 
-try:
-    from collections import OrderedDict
-except ImportError:
-    from .odict import OrderedDict
+from collections import OrderedDict
 
 __version__ = "0.4"
 
diff --git a/sklearn/externals/odict.py b/sklearn/externals/odict.py
deleted file mode 100644
index 28808634b97e3f7896867ac285e6161e920247bf..0000000000000000000000000000000000000000
--- a/sklearn/externals/odict.py
+++ /dev/null
@@ -1,266 +0,0 @@
-# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy.
-# Passes Python2.7's test suite and incorporates all the latest updates.
-# Copyright 2009 Raymond Hettinger
-# http://code.activestate.com/recipes/576693/
-"Ordered dictionary"
-
-try:
-    from thread import get_ident as _get_ident
-except ImportError:
-    try:
-        from dummy_thread import get_ident as _get_ident
-    except ImportError:
-        # Ensure that this module is still importable under Python3 to avoid
-        # crashing code-inspecting tools like nose.
-        from _dummy_thread import get_ident as _get_ident
-
-try:
-    from _abcoll import KeysView, ValuesView, ItemsView
-except ImportError:
-    pass
-
-
-class OrderedDict(dict):
-    'Dictionary that remembers insertion order'
-    # An inherited dict maps keys to values.
-    # The inherited dict provides __getitem__, __len__, __contains__, and get.
-    # The remaining methods are order-aware.
-    # Big-O running times for all methods are the same as for regular dictionaries.
-
-    # The internal self.__map dictionary maps keys to links in a doubly linked list.
-    # The circular doubly linked list starts and ends with a sentinel element.
-    # The sentinel element never gets deleted (this simplifies the algorithm).
-    # Each link is stored as a list of length three:  [PREV, NEXT, KEY].
-
-    def __init__(self, *args, **kwds):
-        '''Initialize an ordered dictionary.  Signature is the same as for
-        regular dictionaries, but keyword arguments are not recommended
-        because their insertion order is arbitrary.
-
-        '''
-        if len(args) > 1:
-            raise TypeError('expected at most 1 arguments, got %d' % len(args))
-        try:
-            self.__root
-        except AttributeError:
-            self.__root = root = []                     # sentinel node
-            root[:] = [root, root, None]
-            self.__map = {}
-        self.__update(*args, **kwds)
-
-    def __setitem__(self, key, value, dict_setitem=dict.__setitem__):
-        'od.__setitem__(i, y) <==> od[i]=y'
-        # Setting a new item creates a new link which goes at the end of the linked
-        # list, and the inherited dictionary is updated with the new key/value pair.
-        if key not in self:
-            root = self.__root
-            last = root[0]
-            last[1] = root[0] = self.__map[key] = [last, root, key]
-        dict_setitem(self, key, value)
-
-    def __delitem__(self, key, dict_delitem=dict.__delitem__):
-        'od.__delitem__(y) <==> del od[y]'
-        # Deleting an existing item uses self.__map to find the link which is
-        # then removed by updating the links in the predecessor and successor nodes.
-        dict_delitem(self, key)
-        link_prev, link_next, key = self.__map.pop(key)
-        link_prev[1] = link_next
-        link_next[0] = link_prev
-
-    def __iter__(self):
-        'od.__iter__() <==> iter(od)'
-        root = self.__root
-        curr = root[1]
-        while curr is not root:
-            yield curr[2]
-            curr = curr[1]
-
-    def __reversed__(self):
-        'od.__reversed__() <==> reversed(od)'
-        root = self.__root
-        curr = root[0]
-        while curr is not root:
-            yield curr[2]
-            curr = curr[0]
-
-    def clear(self):
-        'od.clear() -> None.  Remove all items from od.'
-        try:
-            for node in self.__map.itervalues():
-                del node[:]
-            root = self.__root
-            root[:] = [root, root, None]
-            self.__map.clear()
-        except AttributeError:
-            pass
-        dict.clear(self)
-
-    def popitem(self, last=True):
-        '''od.popitem() -> (k, v), return and remove a (key, value) pair.
-        Pairs are returned in LIFO order if last is true or FIFO order if false.
-
-        '''
-        if not self:
-            raise KeyError('dictionary is empty')
-        root = self.__root
-        if last:
-            link = root[0]
-            link_prev = link[0]
-            link_prev[1] = root
-            root[0] = link_prev
-        else:
-            link = root[1]
-            link_next = link[1]
-            root[1] = link_next
-            link_next[0] = root
-        key = link[2]
-        del self.__map[key]
-        value = dict.pop(self, key)
-        return key, value
-
-    # -- the following methods do not depend on the internal structure --
-
-    def keys(self):
-        'od.keys() -> list of keys in od'
-        return list(self)
-
-    def values(self):
-        'od.values() -> list of values in od'
-        return [self[key] for key in self]
-
-    def items(self):
-        'od.items() -> list of (key, value) pairs in od'
-        return [(key, self[key]) for key in self]
-
-    def iterkeys(self):
-        'od.iterkeys() -> an iterator over the keys in od'
-        return iter(self)
-
-    def itervalues(self):
-        'od.itervalues -> an iterator over the values in od'
-        for k in self:
-            yield self[k]
-
-    def iteritems(self):
-        'od.iteritems -> an iterator over the (key, value) items in od'
-        for k in self:
-            yield (k, self[k])
-
-    def update(*args, **kwds):
-        '''od.update(E, **F) -> None.  Update od from dict/iterable E and F.
-
-        If E is a dict instance, does:           for k in E: od[k] = E[k]
-        If E has a .keys() method, does:         for k in E.keys(): od[k] = E[k]
-        Or if E is an iterable of items, does:   for k, v in E: od[k] = v
-        In either case, this is followed by:     for k, v in F.items(): od[k] = v
-
-        '''
-        if len(args) > 2:
-            raise TypeError('update() takes at most 2 positional '
-                            'arguments (%d given)' % (len(args),))
-        elif not args:
-            raise TypeError('update() takes at least 1 argument (0 given)')
-        self = args[0]
-        # Make progressively weaker assumptions about "other"
-        other = ()
-        if len(args) == 2:
-            other = args[1]
-        if isinstance(other, dict):
-            for key in other:
-                self[key] = other[key]
-        elif hasattr(other, 'keys'):
-            for key in other.keys():
-                self[key] = other[key]
-        else:
-            for key, value in other:
-                self[key] = value
-        for key, value in kwds.items():
-            self[key] = value
-
-    __update = update  # let subclasses override update without breaking __init__
-
-    __marker = object()
-
-    def pop(self, key, default=__marker):
-        '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value.
-        If key is not found, d is returned if given, otherwise KeyError is raised.
-
-        '''
-        if key in self:
-            result = self[key]
-            del self[key]
-            return result
-        if default is self.__marker:
-            raise KeyError(key)
-        return default
-
-    def setdefault(self, key, default=None):
-        'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od'
-        if key in self:
-            return self[key]
-        self[key] = default
-        return default
-
-    def __repr__(self, _repr_running={}):
-        'od.__repr__() <==> repr(od)'
-        call_key = id(self), _get_ident()
-        if call_key in _repr_running:
-            return '...'
-        _repr_running[call_key] = 1
-        try:
-            if not self:
-                return '%s()' % (self.__class__.__name__,)
-            return '%s(%r)' % (self.__class__.__name__, self.items())
-        finally:
-            del _repr_running[call_key]
-
-    def __reduce__(self):
-        'Return state information for pickling'
-        items = [[k, self[k]] for k in self]
-        inst_dict = vars(self).copy()
-        for k in vars(OrderedDict()):
-            inst_dict.pop(k, None)
-        if inst_dict:
-            return (self.__class__, (items,), inst_dict)
-        return self.__class__, (items,)
-
-    def copy(self):
-        'od.copy() -> a shallow copy of od'
-        return self.__class__(self)
-
-    @classmethod
-    def fromkeys(cls, iterable, value=None):
-        '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S
-        and values equal to v (which defaults to None).
-
-        '''
-        d = cls()
-        for key in iterable:
-            d[key] = value
-        return d
-
-    def __eq__(self, other):
-        '''od.__eq__(y) <==> od==y.  Comparison to another OD is order-sensitive
-        while comparison to a regular mapping is order-insensitive.
-
-        '''
-        if isinstance(other, OrderedDict):
-            return len(self)==len(other) and self.items() == other.items()
-        return dict.__eq__(self, other)
-
-    def __ne__(self, other):
-        return not self == other
-
-    # -- the following methods are only used in Python 2.7 --
-
-    def viewkeys(self):
-        "od.viewkeys() -> a set-like object providing a view on od's keys"
-        return KeysView(self)
-
-    def viewvalues(self):
-        "od.viewvalues() -> an object providing a view on od's values"
-        return ValuesView(self)
-
-    def viewitems(self):
-        "od.viewitems() -> a set-like object providing a view on od's items"
-        return ItemsView(self)
diff --git a/sklearn/gaussian_process/gaussian_process.py b/sklearn/gaussian_process/gaussian_process.py
index c521cb5b52f43afa9a9e12981eeb3ad852f2fd2a..eb15e7c936f462bf3f230aef648a9f337c1c5225 100644
--- a/sklearn/gaussian_process/gaussian_process.py
+++ b/sklearn/gaussian_process/gaussian_process.py
@@ -618,14 +618,7 @@ class GaussianProcess(BaseEstimator, RegressorMixin):
 
         # Get generalized least squares solution
         Ft = linalg.solve_triangular(C, F, lower=True)
-        try:
-            Q, G = linalg.qr(Ft, econ=True)
-        except:
-            #/usr/lib/python2.6/dist-packages/scipy/linalg/decomp.py:1177:
-            # DeprecationWarning: qr econ argument will be removed after scipy
-            # 0.7. The economy transform will then be available through the
-            # mode='economic' argument.
-            Q, G = linalg.qr(Ft, mode='economic')
+        Q, G = linalg.qr(Ft, mode='economic')
 
         sv = linalg.svd(G, compute_uv=False)
         rcondG = sv[-1] / sv[0]
diff --git a/sklearn/linear_model/tests/test_coordinate_descent.py b/sklearn/linear_model/tests/test_coordinate_descent.py
index feb66f63f2fb89842c5aca335f68efdb13cd9e0c..507208b24bad574902b05b646e076f22330f970c 100644
--- a/sklearn/linear_model/tests/test_coordinate_descent.py
+++ b/sklearn/linear_model/tests/test_coordinate_descent.py
@@ -32,12 +32,6 @@ from sklearn.linear_model import LassoLarsCV, lars_path
 from sklearn.utils import check_array
 
 
-def check_warnings():
-    if version_info < (2, 6):
-        raise SkipTest("Testing for warnings is not supported in versions \
-        older than Python 2.6")
-
-
 def test_lasso_zero():
     # Check that the lasso can handle zero data without crashing
     X = [[0], [0], [0]]
diff --git a/sklearn/metrics/classification.py b/sklearn/metrics/classification.py
index ee07fa634d08058b271633755354a3360b59d063..43e4d1554f213d308b8549dc2e6147c7d2629ba3 100644
--- a/sklearn/metrics/classification.py
+++ b/sklearn/metrics/classification.py
@@ -430,10 +430,6 @@ def jaccard_similarity_score(y_true, y_pred, normalize=True,
             pred_or_true = count_nonzero(y_true + y_pred, axis=1)
             pred_and_true = count_nonzero(y_true.multiply(y_pred), axis=1)
             score = pred_and_true / pred_or_true
-
-            # If there is no label, it results in a Nan instead, we set
-            # the jaccard to 1: lim_{x->0} x/x = 1
-            # Note with py2.6 and np 1.3: we can't check safely for nan.
             score[pred_or_true == 0.0] = 1.0
     else:
         score = y_true == y_pred
diff --git a/sklearn/metrics/pairwise.py b/sklearn/metrics/pairwise.py
index e7599b65fb0fcaeb714a31017e1f160832f6fd03..2258f070018d24cbc04397b46747aa756acaafa4 100644
--- a/sklearn/metrics/pairwise.py
+++ b/sklearn/metrics/pairwise.py
@@ -10,6 +10,7 @@
 # License: BSD 3 clause
 
 import itertools
+from functools import partial
 
 import numpy as np
 from scipy.spatial import distance
@@ -19,7 +20,6 @@ from scipy.sparse import issparse
 from ..utils import check_array
 from ..utils import gen_even_slices
 from ..utils import gen_batches
-from ..utils.fixes import partial
 from ..utils.extmath import row_norms, safe_sparse_dot
 from ..preprocessing import normalize
 from ..externals.joblib import Parallel
diff --git a/sklearn/model_selection/tests/test_split.py b/sklearn/model_selection/tests/test_split.py
index 660b0b1781935ba5e7766b669305ae97cb1aebdc..fba323492be856666d9923f777347058576dce03 100644
--- a/sklearn/model_selection/tests/test_split.py
+++ b/sklearn/model_selection/tests/test_split.py
@@ -7,7 +7,7 @@ from scipy.sparse import coo_matrix, csc_matrix, csr_matrix
 from scipy import stats
 from scipy.misc import comb
 from itertools import combinations
-from sklearn.utils.fixes import combinations_with_replacement
+from itertools import combinations_with_replacement
 
 from sklearn.utils.testing import assert_true
 from sklearn.utils.testing import assert_false
diff --git a/sklearn/neighbors/tests/test_approximate.py b/sklearn/neighbors/tests/test_approximate.py
index 792eccda441617d9e93919290ee2b3d6e759934b..4d87ad6796a2a6e9ba7b4b0dcf0f8f65b2508aba 100644
--- a/sklearn/neighbors/tests/test_approximate.py
+++ b/sklearn/neighbors/tests/test_approximate.py
@@ -229,7 +229,8 @@ def test_radius_neighbors_boundary_handling():
 
     # Build a LSHForest model with hyperparameter values that always guarantee
     # exact results on this toy dataset.
-    lsfh = LSHForest(min_hash_match=0, n_candidates=n_points).fit(X)
+    lsfh = LSHForest(min_hash_match=0, n_candidates=n_points,
+                     random_state=42).fit(X)
 
     # define a query aligned with the first axis
     query = [[1., 0.]]
diff --git a/sklearn/preprocessing/data.py b/sklearn/preprocessing/data.py
index a633bb44251e26a8933916e9d245d38880c3a012..307e2f47e7d1ae1050ed9dc20c32dd2ab42d951e 100644
--- a/sklearn/preprocessing/data.py
+++ b/sklearn/preprocessing/data.py
@@ -9,6 +9,7 @@
 from itertools import chain, combinations
 import numbers
 import warnings
+from itertools import combinations_with_replacement as combinations_w_r
 
 import numpy as np
 from scipy import sparse
@@ -19,7 +20,6 @@ from ..utils import check_array
 from ..utils import deprecated
 from ..utils.extmath import row_norms
 from ..utils.extmath import _incremental_mean_and_var
-from ..utils.fixes import combinations_with_replacement as combinations_w_r
 from ..utils.fixes import bincount
 from ..utils.sparsefuncs_fast import (inplace_csr_row_normalize_l1,
                                       inplace_csr_row_normalize_l2)
diff --git a/sklearn/tests/test_base.py b/sklearn/tests/test_base.py
index d0df21c7804665ee1d291b96b86512e9c3e104b7..9983dbdc486bd5d76339b26b81e6b2dc5deb74eb 100644
--- a/sklearn/tests/test_base.py
+++ b/sklearn/tests/test_base.py
@@ -180,11 +180,6 @@ def test_clone_sparse_matrices():
         getattr(sp, name)
         for name in dir(sp) if name.endswith('_matrix')]
 
-    PY26 = sys.version_info[:2] == (2, 6)
-    if PY26:
-        # sp.dok_matrix can not be deepcopied in Python 2.6
-        sparse_matrix_classes.remove(sp.dok_matrix)
-
     for cls in sparse_matrix_classes:
         sparse_matrix = cls(np.eye(5))
         clf = MyEstimator(empty=sparse_matrix)
diff --git a/sklearn/utils/fixes.py b/sklearn/utils/fixes.py
index c7bc8f3078d6b118d88f887aca28ecdb6f01dbd4..35dcb9b7ee0e2ffdbdade574ae19ab259fcf26e2 100644
--- a/sklearn/utils/fixes.py
+++ b/sklearn/utils/fixes.py
@@ -204,30 +204,6 @@ except ImportError:
         return np.sort(a, axis=axis, order=order)
 
 
-try:
-    from itertools import combinations_with_replacement
-except ImportError:
-    # Backport of itertools.combinations_with_replacement for Python 2.6,
-    # from Python 3.4 documentation (http://tinyurl.com/comb-w-r), copyright
-    # Python Software Foundation (https://docs.python.org/3/license.html)
-    def combinations_with_replacement(iterable, r):
-        # combinations_with_replacement('ABC', 2) --> AA AB AC BB BC CC
-        pool = tuple(iterable)
-        n = len(pool)
-        if not n and r:
-            return
-        indices = [0] * r
-        yield tuple(pool[i] for i in indices)
-        while True:
-            for i in reversed(range(r)):
-                if indices[i] != n - 1:
-                    break
-            else:
-                return
-            indices[i:] = [indices[i] + 1] * (r - i)
-            yield tuple(pool[i] for i in indices)
-
-
 if np_version < (1, 7):
     # Prior to 1.7.0, np.frombuffer wouldn't work for empty first arg.
     def frombuffer_empty(buf, dtype):
@@ -291,25 +267,6 @@ else:
     from scipy.sparse.linalg import lsqr as sparse_lsqr
 
 
-if sys.version_info < (2, 7, 0):
-    # partial cannot be pickled in Python 2.6
-    # http://bugs.python.org/issue1398
-    class partial(object):
-        def __init__(self, func, *args, **keywords):
-            functools.update_wrapper(self, func)
-            self.func = func
-            self.args = args
-            self.keywords = keywords
-
-        def __call__(self, *args, **keywords):
-            args = self.args + args
-            kwargs = self.keywords.copy()
-            kwargs.update(keywords)
-            return self.func(*args, **kwargs)
-else:
-    from functools import partial
-
-
 def parallel_helper(obj, methodname, *args, **kwargs):
     """Helper to workaround Python 2 limitations of pickling instance methods"""
     return getattr(obj, methodname)(*args, **kwargs)
diff --git a/sklearn/utils/testing.py b/sklearn/utils/testing.py
index 1146b4f645048b1e6b1b00cea17535329c25fbb8..ce5465ad1f0a8bbdb1d26447f5b7a5bad317be06 100644
--- a/sklearn/utils/testing.py
+++ b/sklearn/utils/testing.py
@@ -77,85 +77,27 @@ assert_not_equal = _dummy.assertNotEqual
 assert_true = _dummy.assertTrue
 assert_false = _dummy.assertFalse
 assert_raises = _dummy.assertRaises
-
-try:
-    SkipTest = unittest.case.SkipTest
-except AttributeError:
-    # Python <= 2.6, we stil need nose here
-    from nose import SkipTest
+SkipTest = unittest.case.SkipTest
+assert_dict_equal = _dummy.assertDictEqual
+assert_in = _dummy.assertIn
+assert_not_in = _dummy.assertNotIn
+assert_less = _dummy.assertLess
+assert_greater = _dummy.assertGreater
+assert_less_equal = _dummy.assertLessEqual
+assert_greater_equal = _dummy.assertGreaterEqual
 
 
-try:
-    assert_dict_equal = _dummy.assertDictEqual
-    assert_in = _dummy.assertIn
-    assert_not_in = _dummy.assertNotIn
-except AttributeError:
-    # Python <= 2.6
-
-    assert_dict_equal = assert_equal
-
-    def assert_in(x, container):
-        assert_true(x in container, msg="%r in %r" % (x, container))
-
-    def assert_not_in(x, container):
-        assert_false(x in container, msg="%r in %r" % (x, container))
-
 try:
     assert_raises_regex = _dummy.assertRaisesRegex
 except AttributeError:
-    # for Python 2.6
-    def assert_raises_regex(expected_exception, expected_regexp,
-                            callable_obj=None, *args, **kwargs):
-        """Helper function to check for message patterns in exceptions."""
-        not_raised = False
-        try:
-            callable_obj(*args, **kwargs)
-            not_raised = True
-        except expected_exception as e:
-            error_message = str(e)
-            if not re.compile(expected_regexp).search(error_message):
-                raise AssertionError("Error message should match pattern "
-                                     "%r. %r does not." %
-                                     (expected_regexp, error_message))
-        if not_raised:
-            raise AssertionError("%s not raised by %s" %
-                                 (expected_exception.__name__,
-                                  callable_obj.__name__))
-
+    # Python 2.7
+    assert_raises_regex = _dummy.assertRaisesRegexp
 # assert_raises_regexp is deprecated in Python 3.4 in favor of
 # assert_raises_regex but lets keep the backward compat in scikit-learn with
 # the old name for now
 assert_raises_regexp = assert_raises_regex
 
 
-def _assert_less(a, b, msg=None):
-    message = "%r is not lower than %r" % (a, b)
-    if msg is not None:
-        message += ": " + msg
-    assert a < b, message
-
-
-def _assert_greater(a, b, msg=None):
-    message = "%r is not greater than %r" % (a, b)
-    if msg is not None:
-        message += ": " + msg
-    assert a > b, message
-
-
-def assert_less_equal(a, b, msg=None):
-    message = "%r is not lower than or equal to %r" % (a, b)
-    if msg is not None:
-        message += ": " + msg
-    assert a <= b, message
-
-
-def assert_greater_equal(a, b, msg=None):
-    message = "%r is not greater than or equal to %r" % (a, b)
-    if msg is not None:
-        message += ": " + msg
-    assert a >= b, message
-
-
 def assert_warns(warning_class, func, *args, **kw):
     """Test that a certain warning occurs.
 
@@ -273,9 +215,6 @@ def assert_warns_message(warning_class, message, func, *args, **kw):
 
 # To remove when we support numpy 1.7
 def assert_no_warnings(func, *args, **kw):
-    # XXX: once we may depend on python >= 2.6, this can be replaced by the
-
-    # warnings module context manager.
     # very important to avoid uncontrolled state propagation
     clean_warning_registry()
     with warnings.catch_warnings(record=True) as w:
@@ -384,12 +323,8 @@ class _IgnoreWarnings(object):
         clean_warning_registry()  # be safe and not propagate state + chaos
 
 
-try:
-    assert_less = _dummy.assertLess
-    assert_greater = _dummy.assertGreater
-except AttributeError:
-    assert_less = _assert_less
-    assert_greater = _assert_greater
+assert_less = _dummy.assertLess
+assert_greater = _dummy.assertGreater
 
 
 def _assert_allclose(actual, desired, rtol=1e-7, atol=0,
diff --git a/sklearn/utils/tests/test_estimator_checks.py b/sklearn/utils/tests/test_estimator_checks.py
index de7e1e2f2ac1b94366433fa2e150181d17d0f48c..d937a2fbfbae9b647f6a76c2b51a94ee144747a4 100644
--- a/sklearn/utils/tests/test_estimator_checks.py
+++ b/sklearn/utils/tests/test_estimator_checks.py
@@ -84,7 +84,7 @@ def test_check_estimator():
     msg = "object has no attribute 'fit'"
     assert_raises_regex(AttributeError, msg, check_estimator, BaseEstimator)
     # check that fit does input validation
-    msg = "TypeError not raised by fit"
+    msg = "TypeError not raised"
     assert_raises_regex(AssertionError, msg, check_estimator, BaseBadClassifier)
     # check that predict does input validation (doesn't accept dicts in input)
     msg = "Estimator doesn't check for NaN and inf in predict"
diff --git a/sklearn/utils/tests/test_testing.py b/sklearn/utils/tests/test_testing.py
index 17e9209dbce851dd86bd99116e202ea8873d0ecd..10657682e5cf1ce444f978ccddc216c8bb029e38 100644
--- a/sklearn/utils/tests/test_testing.py
+++ b/sklearn/utils/tests/test_testing.py
@@ -4,8 +4,8 @@ import sys
 
 from sklearn.utils.testing import (
     assert_raises,
-    _assert_less,
-    _assert_greater,
+    assert_less,
+    assert_greater,
     assert_less_equal,
     assert_greater_equal,
     assert_warns,
@@ -18,33 +18,15 @@ from sklearn.utils.testing import (
 from sklearn.tree import DecisionTreeClassifier
 from sklearn.discriminant_analysis import LinearDiscriminantAnalysis
 
-try:
-    from nose.tools import assert_less
-
-    def test_assert_less():
-        # Check that the nose implementation of assert_less gives the
-        # same thing as the scikit's
-        assert_less(0, 1)
-        _assert_less(0, 1)
-        assert_raises(AssertionError, assert_less, 1, 0)
-        assert_raises(AssertionError, _assert_less, 1, 0)
-
-except ImportError:
-    pass
-
-try:
-    from nose.tools import assert_greater
-
-    def test_assert_greater():
-        # Check that the nose implementation of assert_less gives the
-        # same thing as the scikit's
-        assert_greater(1, 0)
-        _assert_greater(1, 0)
-        assert_raises(AssertionError, assert_greater, 0, 1)
-        assert_raises(AssertionError, _assert_greater, 0, 1)
-
-except ImportError:
-    pass
+
+def test_assert_less():
+    assert_less(0, 1)
+    assert_raises(AssertionError, assert_less, 1, 0)
+
+
+def test_assert_greater():
+    assert_greater(1, 0)
+    assert_raises(AssertionError, assert_greater, 0, 1)
 
 
 def test_assert_less_equal():