~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/util/_bencode_py.py

Add bzrlib.pyutils, which has get_named_object, a wrapper around __import__.

This is used to replace various ad hoc implementations of the same logic,
notably the version used in registry's _LazyObjectGetter which had a bug when
getting a module without also getting a member.  And of course, this new
function has unit tests, unlike the replaced code.

This also adds a KnownHooksRegistry subclass to provide a more natural home for
some other logic.

I'm not thrilled about the name of the new module or the new functions, but it's
hard to think of good names for such generic functionality.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# bencode structured encoding
 
2
#
 
3
# Written by Petru Paler
 
4
#
 
5
# Permission is hereby granted, free of charge, to any person
 
6
# obtaining a copy of this software and associated documentation files
 
7
# (the "Software"), to deal in the Software without restriction,
 
8
# including without limitation the rights to use, copy, modify, merge,
 
9
# publish, distribute, sublicense, and/or sell copies of the Software,
 
10
# and to permit persons to whom the Software is furnished to do so,
 
11
# subject to the following conditions:
 
12
#
 
13
# The above copyright notice and this permission notice shall be
 
14
# included in all copies or substantial portions of the Software.
 
15
#
 
16
# Modifications copyright (C) 2008 Canonical Ltd
 
17
 
 
18
class BDecoder(object):
 
19
 
 
20
    def __init__(self, yield_tuples=False):
 
21
        """Constructor.
 
22
 
 
23
        :param yield_tuples: if true, decode "l" elements as tuples rather than
 
24
            lists.
 
25
        """
 
26
        self.yield_tuples = yield_tuples
 
27
        decode_func = {}
 
28
        decode_func['l'] = self.decode_list
 
29
        decode_func['d'] = self.decode_dict
 
30
        decode_func['i'] = self.decode_int
 
31
        decode_func['0'] = self.decode_string
 
32
        decode_func['1'] = self.decode_string
 
33
        decode_func['2'] = self.decode_string
 
34
        decode_func['3'] = self.decode_string
 
35
        decode_func['4'] = self.decode_string
 
36
        decode_func['5'] = self.decode_string
 
37
        decode_func['6'] = self.decode_string
 
38
        decode_func['7'] = self.decode_string
 
39
        decode_func['8'] = self.decode_string
 
40
        decode_func['9'] = self.decode_string
 
41
        self.decode_func = decode_func
 
42
 
 
43
    def decode_int(self, x, f):
 
44
        f += 1
 
45
        newf = x.index('e', f)
 
46
        try:
 
47
            n = int(x[f:newf])
 
48
        except (OverflowError, ValueError):
 
49
            n = long(x[f:newf])
 
50
        if x[f] == '-':
 
51
            if x[f + 1] == '0':
 
52
                raise ValueError
 
53
        elif x[f] == '0' and newf != f+1:
 
54
            raise ValueError
 
55
        return (n, newf+1)
 
56
 
 
57
    def decode_string(self, x, f):
 
58
        colon = x.index(':', f)
 
59
        try:
 
60
            n = int(x[f:colon])
 
61
        except (OverflowError, ValueError):
 
62
            n = long(x[f:colon])
 
63
        if x[f] == '0' and colon != f+1:
 
64
            raise ValueError
 
65
        colon += 1
 
66
        return (x[colon:colon+n], colon+n)
 
67
 
 
68
    def decode_list(self, x, f):
 
69
        r, f = [], f+1
 
70
        while x[f] != 'e':
 
71
            v, f = self.decode_func[x[f]](x, f)
 
72
            r.append(v)
 
73
        if self.yield_tuples:
 
74
            r = tuple(r)
 
75
        return (r, f + 1)
 
76
 
 
77
    def decode_dict(self, x, f):
 
78
        r, f = {}, f+1
 
79
        lastkey = None
 
80
        while x[f] != 'e':
 
81
            k, f = self.decode_string(x, f)
 
82
            if lastkey >= k:
 
83
                raise ValueError
 
84
            lastkey = k
 
85
            r[k], f = self.decode_func[x[f]](x, f)
 
86
        return (r, f + 1)
 
87
 
 
88
    def bdecode(self, x):
 
89
        if type(x) != str:
 
90
            raise TypeError
 
91
        try:
 
92
            r, l = self.decode_func[x[0]](x, 0)
 
93
        except (IndexError, KeyError, OverflowError), e:
 
94
            import sys
 
95
            raise ValueError, ValueError(str(e)), sys.exc_info()[2]
 
96
        if l != len(x):
 
97
            raise ValueError
 
98
        return r
 
99
 
 
100
 
 
101
_decoder = BDecoder()
 
102
bdecode = _decoder.bdecode
 
103
 
 
104
_tuple_decoder = BDecoder(True)
 
105
bdecode_as_tuple = _tuple_decoder.bdecode
 
106
 
 
107
 
 
108
from types import StringType, IntType, LongType, DictType, ListType, TupleType
 
109
 
 
110
class Bencached(object):
 
111
    __slots__ = ['bencoded']
 
112
 
 
113
    def __init__(self, s):
 
114
        self.bencoded = s
 
115
 
 
116
def encode_bencached(x,r):
 
117
    r.append(x.bencoded)
 
118
 
 
119
def encode_int(x, r):
 
120
    r.extend(('i', str(x), 'e'))
 
121
 
 
122
def encode_string(x, r):
 
123
    r.extend((str(len(x)), ':', x))
 
124
 
 
125
def encode_list(x, r):
 
126
    r.append('l')
 
127
    for i in x:
 
128
        encode_func[type(i)](i, r)
 
129
    r.append('e')
 
130
 
 
131
def encode_dict(x,r):
 
132
    r.append('d')
 
133
    ilist = x.items()
 
134
    ilist.sort()
 
135
    for k, v in ilist:
 
136
        r.extend((str(len(k)), ':', k))
 
137
        encode_func[type(v)](v, r)
 
138
    r.append('e')
 
139
 
 
140
encode_func = {}
 
141
encode_func[type(Bencached(0))] = encode_bencached
 
142
encode_func[IntType] = encode_int
 
143
encode_func[LongType] = encode_int
 
144
encode_func[StringType] = encode_string
 
145
encode_func[ListType] = encode_list
 
146
encode_func[TupleType] = encode_list
 
147
encode_func[DictType] = encode_dict
 
148
 
 
149
try:
 
150
    from types import BooleanType
 
151
except ImportError:
 
152
    pass
 
153
else:
 
154
    def encode_bool(x,r):
 
155
        encode_int(int(x), r)
 
156
    encode_func[BooleanType] = encode_bool
 
157
 
 
158
from bzrlib._static_tuple_py import StaticTuple
 
159
encode_func[StaticTuple] = encode_list
 
160
try:
 
161
    from bzrlib._static_tuple_c import StaticTuple
 
162
except ImportError:
 
163
    pass
 
164
else:
 
165
    encode_func[StaticTuple] = encode_list
 
166
 
 
167
 
 
168
def bencode(x):
 
169
    r = []
 
170
    encode_func[type(x)](x, r)
 
171
    return ''.join(r)
 
172