client: don't assume server response is of length 20
[jelmer/dulwich-libgit2.git] / dulwich / misc.py
1 # misc.py -- For dealing with python2.4 oddness
2 # Copyright (C) 2008 Canonical Ltd.
3
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; version 2
7 # of the License or (at your option) a later version.
8
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 # GNU General Public License for more details.
13
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17 # MA  02110-1301, USA.
18 """Misc utilities to work with python2.4.
19
20 These utilities can all be deleted when dulwich decides it wants to stop
21 support for python 2.4.
22 """
23 try:
24     import hashlib
25 except ImportError:
26     import sha
27 import struct
28
29
30 class defaultdict(dict):
31     """A python 2.4 equivalent of collections.defaultdict."""
32
33     def __init__(self, default_factory=None, *a, **kw):
34         if (default_factory is not None and
35             not hasattr(default_factory, '__call__')):
36             raise TypeError('first argument must be callable')
37         dict.__init__(self, *a, **kw)
38         self.default_factory = default_factory
39
40     def __getitem__(self, key):
41         try:
42             return dict.__getitem__(self, key)
43         except KeyError:
44             return self.__missing__(key)
45
46     def __missing__(self, key):
47         if self.default_factory is None:
48             raise KeyError(key)
49         self[key] = value = self.default_factory()
50         return value
51
52     def __reduce__(self):
53         if self.default_factory is None:
54             args = tuple()
55         else:
56             args = self.default_factory,
57         return type(self), args, None, None, self.items()
58
59     def copy(self):
60         return self.__copy__()
61
62     def __copy__(self):
63         return type(self)(self.default_factory, self)
64
65     def __deepcopy__(self, memo):
66         import copy
67         return type(self)(self.default_factory,
68                           copy.deepcopy(self.items()))
69     def __repr__(self):
70         return 'defaultdict(%s, %s)' % (self.default_factory,
71                                         dict.__repr__(self))
72
73
74 def make_sha(source=''):
75     """A python2.4 workaround for the sha/hashlib module fiasco."""
76     try:
77         return hashlib.sha1(source)
78     except NameError:
79         sha1 = sha.sha(source)
80         return sha1
81
82
83 def unpack_from(fmt, buf, offset=0):
84     """A python2.4 workaround for struct missing unpack_from."""
85     try:
86         return struct.unpack_from(fmt, buf, offset)
87     except AttributeError:
88         b = buf[offset:offset+struct.calcsize(fmt)]
89         return struct.unpack(fmt, b)
90