浏览代码

Drop support for python 2.6.

Jelmer Vernooij 9 年之前
父节点
当前提交
e680479d53
共有 12 个文件被更改,包括 14 次插入1002 次删除
  1. 0 2
      .travis.yml
  2. 0 4
      Makefile
  3. 5 1
      NEWS
  4. 1 1
      dulwich/__init__.py
  5. 0 963
      dulwich/_compat.py
  6. 4 10
      dulwich/config.py
  7. 1 4
      dulwich/contrib/test_swift.py
  8. 1 4
      dulwich/tests/__init__.py
  9. 0 3
      dulwich/tests/test_archive.py
  10. 0 4
      dulwich/tests/test_patch.py
  11. 1 3
      setup.py
  12. 1 3
      tox.ini

+ 0 - 2
.travis.yml

@@ -4,8 +4,6 @@ env:
   global: TEST_RUNNER=unittest PYTHONHASHSEED=random
 matrix:
   include:
-    - python: "2.6"
-      env: TEST_RUNNER=unittest2.__main__ TEST_REQUIRE="gevent geventhttpclient fastimport unittest2"
     - python: "2.7"
       env: TEST_REQUIRE="gevent geventhttpclient fastimport"
     - python: "pypy"

+ 0 - 4
Makefile

@@ -3,11 +3,7 @@ PYFLAKES = pyflakes
 PEP8 = pep8
 SETUP = $(PYTHON) setup.py
 PYDOCTOR ?= pydoctor
-ifeq ($(shell $(PYTHON) -c "import sys; print(sys.version_info >= (2, 7))"),True)
 TESTRUNNER ?= unittest
-else
-TESTRUNNER ?= unittest2.__main__
-endif
 RUNTEST = PYTHONHASHSEED=random PYTHONPATH=.:$(PYTHONPATH) $(PYTHON) -m $(TESTRUNNER) $(TEST_OPTIONS)
 
 DESTDIR=/

+ 5 - 1
NEWS

@@ -1,4 +1,4 @@
-0.12.1	UNRELEASED
+0.13.0	UNRELEASED
 
  IMPROVEMENTS
 
@@ -11,6 +11,10 @@
   * Fix `dulwich.porcelain.status` when used in empty trees.
     (Jelmer Vernooij, #415)
 
+ CHANGES
+
+  * Drop support for Python 2.6.
+
 0.12.0	2015-12-13
 
  IMPROVEMENTS

+ 1 - 1
dulwich/__init__.py

@@ -21,4 +21,4 @@
 
 """Python implementation of the Git file formats and protocols."""
 
-__version__ = (0, 12, 1)
+__version__ = (0, 13, 0)

+ 0 - 963
dulwich/_compat.py

@@ -1,963 +0,0 @@
-# _compat.py -- For dealing with python2.6 oddness
-# Copyright (C) 2012-2014 Jelmer Vernooij and others.
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU General Public License
-# as published by the Free Software Foundation; version 2
-# of the License or (at your option) a later version of the License.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
-# MA  02110-1301, USA.
-
-"""Misc utilities to work with python <2.7.
-
-These utilities can all be deleted when dulwich decides it wants to stop
-support for python <2.7.
-"""
-
-# 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 (C) Raymond Hettinger, MIT license
-
-try:
-    from thread import get_ident as _get_ident
-except ImportError:
-    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)
-
-
-# Copyright 2007 Google, Inc. All Rights Reserved.
-# Licensed to PSF under a Contributor Agreement.
-
-from abc import ABCMeta, abstractmethod
-import sys
-
-### ONE-TRICK PONIES ###
-
-def _hasattr(C, attr):
-    try:
-        return any(attr in B.__dict__ for B in C.__mro__)
-    except AttributeError:
-        # Old-style class
-        return hasattr(C, attr)
-
-
-class Hashable:
-    __metaclass__ = ABCMeta
-
-    @abstractmethod
-    def __hash__(self):
-        return 0
-
-    @classmethod
-    def __subclasshook__(cls, C):
-        if cls is Hashable:
-            try:
-                for B in C.__mro__:
-                    if "__hash__" in B.__dict__:
-                        if B.__dict__["__hash__"]:
-                            return True
-                        break
-            except AttributeError:
-                # Old-style class
-                if getattr(C, "__hash__", None):
-                    return True
-        return NotImplemented
-
-
-class Iterable:
-    __metaclass__ = ABCMeta
-
-    @abstractmethod
-    def __iter__(self):
-        while False:
-            yield None
-
-    @classmethod
-    def __subclasshook__(cls, C):
-        if cls is Iterable:
-            if _hasattr(C, "__iter__"):
-                return True
-        return NotImplemented
-
-Iterable.register(str)
-
-
-class Iterator(Iterable):
-
-    @abstractmethod
-    def next(self):
-        'Return the next item from the iterator. When exhausted, raise StopIteration'
-        raise StopIteration
-
-    def __iter__(self):
-        return self
-
-    @classmethod
-    def __subclasshook__(cls, C):
-        if cls is Iterator:
-            if _hasattr(C, "next") and _hasattr(C, "__iter__"):
-                return True
-        return NotImplemented
-
-
-class Sized:
-    __metaclass__ = ABCMeta
-
-    @abstractmethod
-    def __len__(self):
-        return 0
-
-    @classmethod
-    def __subclasshook__(cls, C):
-        if cls is Sized:
-            if _hasattr(C, "__len__"):
-                return True
-        return NotImplemented
-
-
-class Container:
-    __metaclass__ = ABCMeta
-
-    @abstractmethod
-    def __contains__(self, x):
-        return False
-
-    @classmethod
-    def __subclasshook__(cls, C):
-        if cls is Container:
-            if _hasattr(C, "__contains__"):
-                return True
-        return NotImplemented
-
-
-class Callable:
-    __metaclass__ = ABCMeta
-
-    @abstractmethod
-    def __call__(self, *args, **kwds):
-        return False
-
-    @classmethod
-    def __subclasshook__(cls, C):
-        if cls is Callable:
-            if _hasattr(C, "__call__"):
-                return True
-        return NotImplemented
-
-
-### SETS ###
-
-
-class Set(Sized, Iterable, Container):
-    """A set is a finite, iterable container.
-
-    This class provides concrete generic implementations of all
-    methods except for __contains__, __iter__ and __len__.
-
-    To override the comparisons (presumably for speed, as the
-    semantics are fixed), all you have to do is redefine __le__ and
-    then the other operations will automatically follow suit.
-    """
-
-    def __le__(self, other):
-        if not isinstance(other, Set):
-            return NotImplemented
-        if len(self) > len(other):
-            return False
-        for elem in self:
-            if elem not in other:
-                return False
-        return True
-
-    def __lt__(self, other):
-        if not isinstance(other, Set):
-            return NotImplemented
-        return len(self) < len(other) and self.__le__(other)
-
-    def __gt__(self, other):
-        if not isinstance(other, Set):
-            return NotImplemented
-        return len(self) > len(other) and self.__ge__(other)
-
-    def __ge__(self, other):
-        if not isinstance(other, Set):
-            return NotImplemented
-        if len(self) < len(other):
-            return False
-        for elem in other:
-            if elem not in self:
-                return False
-        return True
-
-    def __eq__(self, other):
-        if not isinstance(other, Set):
-            return NotImplemented
-        return len(self) == len(other) and self.__le__(other)
-
-    def __ne__(self, other):
-        return not (self == other)
-
-    @classmethod
-    def _from_iterable(cls, it):
-        '''Construct an instance of the class from any iterable input.
-
-        Must override this method if the class constructor signature
-        does not accept an iterable for an input.
-        '''
-        return cls(it)
-
-    def __and__(self, other):
-        if not isinstance(other, Iterable):
-            return NotImplemented
-        return self._from_iterable(value for value in other if value in self)
-
-    __rand__ = __and__
-
-    def isdisjoint(self, other):
-        'Return True if two sets have a null intersection.'
-        for value in other:
-            if value in self:
-                return False
-        return True
-
-    def __or__(self, other):
-        if not isinstance(other, Iterable):
-            return NotImplemented
-        chain = (e for s in (self, other) for e in s)
-        return self._from_iterable(chain)
-
-    __ror__ = __or__
-
-    def __sub__(self, other):
-        if not isinstance(other, Set):
-            if not isinstance(other, Iterable):
-                return NotImplemented
-            other = self._from_iterable(other)
-        return self._from_iterable(value for value in self
-                                   if value not in other)
-
-    def __rsub__(self, other):
-        if not isinstance(other, Set):
-            if not isinstance(other, Iterable):
-                return NotImplemented
-            other = self._from_iterable(other)
-        return self._from_iterable(value for value in other
-                                   if value not in self)
-
-    def __xor__(self, other):
-        if not isinstance(other, Set):
-            if not isinstance(other, Iterable):
-                return NotImplemented
-            other = self._from_iterable(other)
-        return (self - other) | (other - self)
-
-    __rxor__ = __xor__
-
-    # Sets are not hashable by default, but subclasses can change this
-    __hash__ = None
-
-    def _hash(self):
-        """Compute the hash value of a set.
-
-        Note that we don't define __hash__: not all sets are hashable.
-        But if you define a hashable set type, its __hash__ should
-        call this function.
-
-        This must be compatible __eq__.
-
-        All sets ought to compare equal if they contain the same
-        elements, regardless of how they are implemented, and
-        regardless of the order of the elements; so there's not much
-        freedom for __eq__ or __hash__.  We match the algorithm used
-        by the built-in frozenset type.
-        """
-        MAX = sys.maxint
-        MASK = 2 * MAX + 1
-        n = len(self)
-        h = 1927868237 * (n + 1)
-        h &= MASK
-        for x in self:
-            hx = hash(x)
-            h ^= (hx ^ (hx << 16) ^ 89869747)  * 3644798167
-            h &= MASK
-        h = h * 69069 + 907133923
-        h &= MASK
-        if h > MAX:
-            h -= MASK + 1
-        if h == -1:
-            h = 590923713
-        return h
-
-Set.register(frozenset)
-
-
-class MutableSet(Set):
-    """A mutable set is a finite, iterable container.
-
-    This class provides concrete generic implementations of all
-    methods except for __contains__, __iter__, __len__,
-    add(), and discard().
-
-    To override the comparisons (presumably for speed, as the
-    semantics are fixed), all you have to do is redefine __le__ and
-    then the other operations will automatically follow suit.
-    """
-
-    @abstractmethod
-    def add(self, value):
-        """Add an element."""
-        raise NotImplementedError
-
-    @abstractmethod
-    def discard(self, value):
-        """Remove an element.  Do not raise an exception if absent."""
-        raise NotImplementedError
-
-    def remove(self, value):
-        """Remove an element. If not a member, raise a KeyError."""
-        if value not in self:
-            raise KeyError(value)
-        self.discard(value)
-
-    def pop(self):
-        """Return the popped value.  Raise KeyError if empty."""
-        it = iter(self)
-        try:
-            value = next(it)
-        except StopIteration:
-            raise KeyError
-        self.discard(value)
-        return value
-
-    def clear(self):
-        """This is slow (creates N new iterators!) but effective."""
-        try:
-            while True:
-                self.pop()
-        except KeyError:
-            pass
-
-    def __ior__(self, it):
-        for value in it:
-            self.add(value)
-        return self
-
-    def __iand__(self, it):
-        for value in (self - it):
-            self.discard(value)
-        return self
-
-    def __ixor__(self, it):
-        if it is self:
-            self.clear()
-        else:
-            if not isinstance(it, Set):
-                it = self._from_iterable(it)
-            for value in it:
-                if value in self:
-                    self.discard(value)
-                else:
-                    self.add(value)
-        return self
-
-    def __isub__(self, it):
-        if it is self:
-            self.clear()
-        else:
-            for value in it:
-                self.discard(value)
-        return self
-
-MutableSet.register(set)
-
-
-### MAPPINGS ###
-
-
-class Mapping(Sized, Iterable, Container):
-
-    """A Mapping is a generic container for associating key/value
-    pairs.
-
-    This class provides concrete generic implementations of all
-    methods except for __getitem__, __iter__, and __len__.
-
-    """
-
-    @abstractmethod
-    def __getitem__(self, key):
-        raise KeyError
-
-    def get(self, key, default=None):
-        'D.get(k[,d]) -> D[k] if k in D, else d.  d defaults to None.'
-        try:
-            return self[key]
-        except KeyError:
-            return default
-
-    def __contains__(self, key):
-        try:
-            self[key]
-        except KeyError:
-            return False
-        else:
-            return True
-
-    def iterkeys(self):
-        'D.iterkeys() -> an iterator over the keys of D'
-        return iter(self)
-
-    def itervalues(self):
-        'D.itervalues() -> an iterator over the values of D'
-        for key in self:
-            yield self[key]
-
-    def iteritems(self):
-        'D.iteritems() -> an iterator over the (key, value) items of D'
-        for key in self:
-            yield (key, self[key])
-
-    def keys(self):
-        "D.keys() -> list of D's keys"
-        return list(self)
-
-    def items(self):
-        "D.items() -> list of D's (key, value) pairs, as 2-tuples"
-        return [(key, self[key]) for key in self]
-
-    def values(self):
-        "D.values() -> list of D's values"
-        return [self[key] for key in self]
-
-    # Mappings are not hashable by default, but subclasses can change this
-    __hash__ = None
-
-    def __eq__(self, other):
-        if not isinstance(other, Mapping):
-            return NotImplemented
-        return dict(self.items()) == dict(other.items())
-
-    def __ne__(self, other):
-        return not (self == other)
-
-class MappingView(Sized):
-
-    def __init__(self, mapping):
-        self._mapping = mapping
-
-    def __len__(self):
-        return len(self._mapping)
-
-    def __repr__(self):
-        return '{0.__class__.__name__}({0._mapping!r})'.format(self)
-
-
-class KeysView(MappingView, Set):
-
-    @classmethod
-    def _from_iterable(self, it):
-        return set(it)
-
-    def __contains__(self, key):
-        return key in self._mapping
-
-    def __iter__(self):
-        for key in self._mapping:
-            yield key
-
-
-class ItemsView(MappingView, Set):
-
-    @classmethod
-    def _from_iterable(self, it):
-        return set(it)
-
-    def __contains__(self, item):
-        key, value = item
-        try:
-            v = self._mapping[key]
-        except KeyError:
-            return False
-        else:
-            return v == value
-
-    def __iter__(self):
-        for key in self._mapping:
-            yield (key, self._mapping[key])
-
-
-class ValuesView(MappingView):
-
-    def __contains__(self, value):
-        for key in self._mapping:
-            if value == self._mapping[key]:
-                return True
-        return False
-
-    def __iter__(self):
-        for key in self._mapping:
-            yield self._mapping[key]
-
-
-class MutableMapping(Mapping):
-
-    """A MutableMapping is a generic container for associating
-    key/value pairs.
-
-    This class provides concrete generic implementations of all
-    methods except for __getitem__, __setitem__, __delitem__,
-    __iter__, and __len__.
-
-    """
-
-    @abstractmethod
-    def __setitem__(self, key, value):
-        raise KeyError
-
-    @abstractmethod
-    def __delitem__(self, key):
-        raise KeyError
-
-    __marker = object()
-
-    def pop(self, key, default=__marker):
-        '''D.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.
-        '''
-        try:
-            value = self[key]
-        except KeyError:
-            if default is self.__marker:
-                raise
-            return default
-        else:
-            del self[key]
-            return value
-
-    def popitem(self):
-        '''D.popitem() -> (k, v), remove and return some (key, value) pair
-           as a 2-tuple; but raise KeyError if D is empty.
-        '''
-        try:
-            key = next(iter(self))
-        except StopIteration:
-            raise KeyError
-        value = self[key]
-        del self[key]
-        return key, value
-
-    def clear(self):
-        'D.clear() -> None.  Remove all items from D.'
-        try:
-            while True:
-                self.popitem()
-        except KeyError:
-            pass
-
-    def update(*args, **kwds):
-        ''' D.update([E, ]**F) -> None.  Update D from mapping/iterable E and F.
-            If E present and has a .keys() method, does:     for k in E: D[k] = E[k]
-            If E present and lacks .keys() method, does:     for (k, v) in E: D[k] = v
-            In either case, this is followed by: for k, v in F.items(): D[k] = v
-        '''
-        if len(args) > 2:
-            raise TypeError("update() takes at most 2 positional "
-                            "arguments ({} given)".format(len(args)))
-        elif not args:
-            raise TypeError("update() takes at least 1 argument (0 given)")
-        self = args[0]
-        other = args[1] if len(args) >= 2 else ()
-
-        if isinstance(other, Mapping):
-            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
-
-    def setdefault(self, key, default=None):
-        'D.setdefault(k[,d]) -> D.get(k,d), also set D[k]=d if k not in D'
-        try:
-            return self[key]
-        except KeyError:
-            self[key] = default
-        return default
-
-MutableMapping.register(dict)
-
-
-### SEQUENCES ###
-
-
-class Sequence(Sized, Iterable, Container):
-    """All the operations on a read-only sequence.
-
-    Concrete subclasses must override __new__ or __init__,
-    __getitem__, and __len__.
-    """
-
-    @abstractmethod
-    def __getitem__(self, index):
-        raise IndexError
-
-    def __iter__(self):
-        i = 0
-        try:
-            while True:
-                v = self[i]
-                yield v
-                i += 1
-        except IndexError:
-            return
-
-    def __contains__(self, value):
-        for v in self:
-            if v == value:
-                return True
-        return False
-
-    def __reversed__(self):
-        for i in reversed(range(len(self))):
-            yield self[i]
-
-    def index(self, value):
-        '''S.index(value) -> integer -- return first index of value.
-           Raises ValueError if the value is not present.
-        '''
-        for i, v in enumerate(self):
-            if v == value:
-                return i
-        raise ValueError
-
-    def count(self, value):
-        'S.count(value) -> integer -- return number of occurrences of value'
-        return sum(1 for v in self if v == value)
-
-Sequence.register(tuple)
-Sequence.register(basestring)
-Sequence.register(buffer)
-Sequence.register(xrange)
-
-
-class MutableSequence(Sequence):
-
-    """All the operations on a read-only sequence.
-
-    Concrete subclasses must provide __new__ or __init__,
-    __getitem__, __setitem__, __delitem__, __len__, and insert().
-
-    """
-
-    @abstractmethod
-    def __setitem__(self, index, value):
-        raise IndexError
-
-    @abstractmethod
-    def __delitem__(self, index):
-        raise IndexError
-
-    @abstractmethod
-    def insert(self, index, value):
-        'S.insert(index, object) -- insert object before index'
-        raise IndexError
-
-    def append(self, value):
-        'S.append(object) -- append object to the end of the sequence'
-        self.insert(len(self), value)
-
-    def reverse(self):
-        'S.reverse() -- reverse *IN PLACE*'
-        n = len(self)
-        for i in range(n//2):
-            self[i], self[n-i-1] = self[n-i-1], self[i]
-
-    def extend(self, values):
-        'S.extend(iterable) -- extend sequence by appending elements from the iterable'
-        for v in values:
-            self.append(v)
-
-    def pop(self, index=-1):
-        '''S.pop([index]) -> item -- remove and return item at index (default last).
-           Raise IndexError if list is empty or index is out of range.
-        '''
-        v = self[index]
-        del self[index]
-        return v
-
-    def remove(self, value):
-        '''S.remove(value) -- remove first occurrence of value.
-           Raise ValueError if the value is not present.
-        '''
-        del self[self.index(value)]
-
-    def __iadd__(self, values):
-        self.extend(values)
-        return self
-
-MutableSequence.register(list)

+ 4 - 10
dulwich/config.py

@@ -27,16 +27,10 @@ TODO:
 import errno
 import os
 
-try:
-    from collections import (
-        OrderedDict,
-        MutableMapping,
-        )
-except ImportError:
-    from dulwich._compat import (
-        OrderedDict,
-        MutableMapping
-        )
+from collections import (
+    OrderedDict,
+    MutableMapping,
+    )
 
 
 from dulwich.file import GitFile

+ 1 - 4
dulwich/contrib/test_swift.py

@@ -25,10 +25,7 @@ import posixpath
 
 from time import time
 from io import BytesIO
-try:
-    from unittest import skipIf
-except ImportError:
-    from unittest2 import skipIf
+from unittest import skipIf
 
 from dulwich.tests import (
     TestCase,

+ 1 - 4
dulwich/tests/__init__.py

@@ -29,10 +29,7 @@ import tempfile
 
 # If Python itself provides an exception, use that
 import unittest
-if sys.version_info < (2, 7):
-    from unittest2 import SkipTest, TestCase as _TestCase, skipIf, expectedFailure
-else:
-    from unittest import SkipTest, TestCase as _TestCase, skipIf, expectedFailure
+from unittest import SkipTest, TestCase as _TestCase, skipIf, expectedFailure
 
 
 def get_safe_env(env=None):

+ 0 - 3
dulwich/tests/test_archive.py

@@ -19,7 +19,6 @@
 """Tests for archive support."""
 
 from io import BytesIO
-import sys
 import tarfile
 
 from dulwich.archive import tar_stream
@@ -41,8 +40,6 @@ from dulwich.tests.utils import (
 class ArchiveTests(TestCase):
 
     def test_empty(self):
-        if sys.version_info[:2] <= (2, 6):
-            self.skipTest("archive creation known failing on Python2.6")
         store = MemoryObjectStore()
         c1, c2, c3 = build_commit_graph(store, [[1], [2, 1], [3, 1, 2]])
         tree = store[c3.tree]

+ 0 - 4
dulwich/tests/test_patch.py

@@ -19,7 +19,6 @@
 """Tests for patch.py."""
 
 from io import BytesIO, StringIO
-import sys
 
 from dulwich.objects import (
     Blob,
@@ -76,9 +75,6 @@ class WriteCommitPatchTests(TestCase):
 class ReadGitAmPatch(TestCase):
 
     def test_extract_string(self):
-        if sys.version_info[:2] <= (2, 6):
-            raise SkipTest("email.parser.Parser.parsestr() inserts extra lines")
-
         text = b"""From ff643aae102d8870cac88e8f007e70f58f3a7363 Mon Sep 17 00:00:00 2001
 From: Jelmer Vernooij <jelmer@samba.org>
 Date: Thu, 15 Apr 2010 15:40:28 +0200

+ 1 - 3
setup.py

@@ -8,7 +8,7 @@ except ImportError:
     from distutils.core import setup, Extension
 from distutils.core import Distribution
 
-dulwich_version_string = '0.12.1'
+dulwich_version_string = '0.13.0'
 
 include_dirs = []
 # Windows MSVC support
@@ -51,8 +51,6 @@ if sys.version_info[0] == 2:
     if not '__pypy__' in sys.modules and not sys.platform == 'win32':
         tests_require.extend([
             'gevent', 'geventhttpclient', 'mock', 'setuptools>=17.1'])
-    if sys.version_info < (2, 7):
-        tests_require.append('unittest2')
 else:
     # fastimport, gevent, geventhttpclient are not available for PY3
     # mock only used for test_swift, which requires gevent/geventhttpclient

+ 1 - 3
tox.ini

@@ -1,10 +1,8 @@
 [tox]
 downloadcache = {toxworkdir}/cache/
-envlist = py26, py27, pypy, py27-noext, pypy-noext, py34, py34-noext, py35, py35-noext
+envlist = py27, pypy, py27-noext, pypy-noext, py34, py34-noext, py35, py35-noext
 
 [testenv]
-deps =
-    unittest2
 
 commands = make check
 recreate = True