~ubuntu-branches/ubuntu/precise/dulwich/precise-security

« back to all changes in this revision

Viewing changes to dulwich/_compat.py

  • Committer: Bazaar Package Importer
  • Author(s): Jelmer Vernooij
  • Date: 2011-08-07 15:03:44 UTC
  • mto: This revision was merged to the branch mainline in revision 25.
  • Revision ID: james.westby@ubuntu.com-20110807150344-94xw3o3hnh47y1m8
Tags: upstream-0.8.0
ImportĀ upstreamĀ versionĀ 0.8.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
32
32
    from cgi import parse_qs
33
33
 
34
34
try:
35
 
    from os import SEEK_END
 
35
    from os import SEEK_CUR, SEEK_END
36
36
except ImportError:
 
37
    SEEK_CUR = 1
37
38
    SEEK_END = 2
38
39
 
39
40
import struct
136
137
 
137
138
 
138
139
try:
 
140
    all = all
 
141
except NameError:
 
142
    # Implementation of permutations from Python 2.6 documentation:
 
143
    # http://docs.python.org/2.6/library/functions.html#all
 
144
    # Copyright (c) 2001-2010 Python Software Foundation; All Rights Reserved
 
145
    # Licensed under the Python Software Foundation License.
 
146
    def all(iterable):
 
147
        for element in iterable:
 
148
            if not element:
 
149
                return False
 
150
        return True
 
151
 
 
152
 
 
153
try:
139
154
    from collections import namedtuple
140
 
 
141
 
    TreeEntryTuple = namedtuple('TreeEntryTuple', ['path', 'mode', 'sha'])
142
 
    TreeChangeTuple = namedtuple('TreeChangeTuple', ['type', 'old', 'new'])
143
155
except ImportError:
144
 
    # Provide manual implementations of namedtuples for Python <2.5.
145
 
    # If the class definitions change, be sure to keep these in sync by running
146
 
    # namedtuple(..., verbose=True) in a recent Python and pasting the output.
147
 
 
148
 
    # Necessary globals go here.
149
 
    _tuple = tuple
150
 
    _property = property
 
156
    # Recipe for namedtuple from http://code.activestate.com/recipes/500261/
 
157
    # Copyright (c) 2007 Python Software Foundation; All Rights Reserved
 
158
    # Licensed under the Python Software Foundation License.
151
159
    from operator import itemgetter as _itemgetter
152
 
 
153
 
    class TreeEntryTuple(tuple):
154
 
            'TreeEntryTuple(path, mode, sha)'
155
 
 
156
 
            __slots__ = ()
157
 
 
158
 
            _fields = ('path', 'mode', 'sha')
159
 
 
160
 
            def __new__(_cls, path, mode, sha):
161
 
                return _tuple.__new__(_cls, (path, mode, sha))
162
 
 
163
 
            @classmethod
164
 
            def _make(cls, iterable, new=tuple.__new__, len=len):
165
 
                'Make a new TreeEntryTuple object from a sequence or iterable'
166
 
                result = new(cls, iterable)
167
 
                if len(result) != 3:
168
 
                    raise TypeError('Expected 3 arguments, got %d' % len(result))
169
 
                return result
170
 
 
171
 
            def __repr__(self):
172
 
                return 'TreeEntryTuple(path=%r, mode=%r, sha=%r)' % self
173
 
 
174
 
            def _asdict(t):
175
 
                'Return a new dict which maps field names to their values'
176
 
                return {'path': t[0], 'mode': t[1], 'sha': t[2]}
177
 
 
178
 
            def _replace(_self, **kwds):
179
 
                'Return a new TreeEntryTuple object replacing specified fields with new values'
180
 
                result = _self._make(map(kwds.pop, ('path', 'mode', 'sha'), _self))
181
 
                if kwds:
182
 
                    raise ValueError('Got unexpected field names: %r' % kwds.keys())
183
 
                return result
184
 
 
185
 
            def __getnewargs__(self):
186
 
                return tuple(self)
187
 
 
188
 
            path = _property(_itemgetter(0))
189
 
            mode = _property(_itemgetter(1))
190
 
            sha = _property(_itemgetter(2))
191
 
 
192
 
 
193
 
    class TreeChangeTuple(tuple):
194
 
            'TreeChangeTuple(type, old, new)'
195
 
 
196
 
            __slots__ = ()
197
 
 
198
 
            _fields = ('type', 'old', 'new')
199
 
 
200
 
            def __new__(_cls, type, old, new):
201
 
                return _tuple.__new__(_cls, (type, old, new))
202
 
 
203
 
            @classmethod
204
 
            def _make(cls, iterable, new=tuple.__new__, len=len):
205
 
                'Make a new TreeChangeTuple object from a sequence or iterable'
206
 
                result = new(cls, iterable)
207
 
                if len(result) != 3:
208
 
                    raise TypeError('Expected 3 arguments, got %d' % len(result))
209
 
                return result
210
 
 
211
 
            def __repr__(self):
212
 
                return 'TreeChangeTuple(type=%r, old=%r, new=%r)' % self
213
 
 
214
 
            def _asdict(t):
215
 
                'Return a new dict which maps field names to their values'
216
 
                return {'type': t[0], 'old': t[1], 'new': t[2]}
217
 
 
218
 
            def _replace(_self, **kwds):
219
 
                'Return a new TreeChangeTuple object replacing specified fields with new values'
220
 
                result = _self._make(map(kwds.pop, ('type', 'old', 'new'), _self))
221
 
                if kwds:
222
 
                    raise ValueError('Got unexpected field names: %r' % kwds.keys())
223
 
                return result
224
 
 
225
 
            def __getnewargs__(self):
226
 
                return tuple(self)
227
 
 
228
 
            type = _property(_itemgetter(0))
229
 
            old = _property(_itemgetter(1))
230
 
            new = _property(_itemgetter(2))
 
160
    from keyword import iskeyword as _iskeyword
 
161
    import sys as _sys
 
162
 
 
163
    def namedtuple(typename, field_names, verbose=False, rename=False):
 
164
        """Returns a new subclass of tuple with named fields.
 
165
 
 
166
        >>> Point = namedtuple('Point', 'x y')
 
167
        >>> Point.__doc__                   # docstring for the new class
 
168
        'Point(x, y)'
 
169
        >>> p = Point(11, y=22)             # instantiate with positional args or keywords
 
170
        >>> p[0] + p[1]                     # indexable like a plain tuple
 
171
        33
 
172
        >>> x, y = p                        # unpack like a regular tuple
 
173
        >>> x, y
 
174
        (11, 22)
 
175
        >>> p.x + p.y                       # fields also accessable by name
 
176
        33
 
177
        >>> d = p._asdict()                 # convert to a dictionary
 
178
        >>> d['x']
 
179
        11
 
180
        >>> Point(**d)                      # convert from a dictionary
 
181
        Point(x=11, y=22)
 
182
        >>> p._replace(x=100)               # _replace() is like str.replace() but targets named fields
 
183
        Point(x=100, y=22)
 
184
 
 
185
        """
 
186
 
 
187
        # Parse and validate the field names.  Validation serves two purposes,
 
188
        # generating informative error messages and preventing template injection attacks.
 
189
        if isinstance(field_names, basestring):
 
190
            field_names = field_names.replace(',', ' ').split() # names separated by whitespace and/or commas
 
191
        field_names = tuple(map(str, field_names))
 
192
        if rename:
 
193
            names = list(field_names)
 
194
            seen = set()
 
195
            for i, name in enumerate(names):
 
196
                if (not min(c.isalnum() or c=='_' for c in name) or _iskeyword(name)
 
197
                    or not name or name[0].isdigit() or name.startswith('_')
 
198
                    or name in seen):
 
199
                        names[i] = '_%d' % i
 
200
                seen.add(name)
 
201
            field_names = tuple(names)
 
202
        for name in (typename,) + field_names:
 
203
            if not min(c.isalnum() or c=='_' for c in name):
 
204
                raise ValueError('Type names and field names can only contain alphanumeric characters and underscores: %r' % name)
 
205
            if _iskeyword(name):
 
206
                raise ValueError('Type names and field names cannot be a keyword: %r' % name)
 
207
            if name[0].isdigit():
 
208
                raise ValueError('Type names and field names cannot start with a number: %r' % name)
 
209
        seen_names = set()
 
210
        for name in field_names:
 
211
            if name.startswith('_') and not rename:
 
212
                raise ValueError('Field names cannot start with an underscore: %r' % name)
 
213
            if name in seen_names:
 
214
                raise ValueError('Encountered duplicate field name: %r' % name)
 
215
            seen_names.add(name)
 
216
 
 
217
        # Create and fill-in the class template
 
218
        numfields = len(field_names)
 
219
        argtxt = repr(field_names).replace("'", "")[1:-1]   # tuple repr without parens or quotes
 
220
        reprtxt = ', '.join('%s=%%r' % name for name in field_names)
 
221
        template = '''class %(typename)s(tuple):
 
222
        '%(typename)s(%(argtxt)s)' \n
 
223
        __slots__ = () \n
 
224
        _fields = %(field_names)r \n
 
225
        def __new__(_cls, %(argtxt)s):
 
226
            return _tuple.__new__(_cls, (%(argtxt)s)) \n
 
227
        @classmethod
 
228
        def _make(cls, iterable, new=tuple.__new__, len=len):
 
229
            'Make a new %(typename)s object from a sequence or iterable'
 
230
            result = new(cls, iterable)
 
231
            if len(result) != %(numfields)d:
 
232
                raise TypeError('Expected %(numfields)d arguments, got %%d' %% len(result))
 
233
            return result \n
 
234
        def __repr__(self):
 
235
            return '%(typename)s(%(reprtxt)s)' %% self \n
 
236
        def _asdict(self):
 
237
            'Return a new dict which maps field names to their values'
 
238
            return dict(zip(self._fields, self)) \n
 
239
        def _replace(_self, **kwds):
 
240
            'Return a new %(typename)s object replacing specified fields with new values'
 
241
            result = _self._make(map(kwds.pop, %(field_names)r, _self))
 
242
            if kwds:
 
243
                raise ValueError('Got unexpected field names: %%r' %% kwds.keys())
 
244
            return result \n
 
245
        def __getnewargs__(self):
 
246
            return tuple(self) \n\n''' % locals()
 
247
        for i, name in enumerate(field_names):
 
248
            template += '        %s = _property(_itemgetter(%d))\n' % (name, i)
 
249
        if verbose:
 
250
            print template
 
251
 
 
252
        # Execute the template string in a temporary namespace
 
253
        namespace = dict(_itemgetter=_itemgetter, __name__='namedtuple_%s' % typename,
 
254
                         _property=property, _tuple=tuple)
 
255
        try:
 
256
            exec template in namespace
 
257
        except SyntaxError, e:
 
258
            raise SyntaxError(e.message + ':\n' + template)
 
259
        result = namespace[typename]
 
260
 
 
261
        # For pickling to work, the __module__ variable needs to be set to the frame
 
262
        # where the named tuple is created.  Bypass this step in enviroments where
 
263
        # sys._getframe is not defined (Jython for example) or sys._getframe is not
 
264
        # defined for arguments greater than 0 (IronPython).
 
265
        try:
 
266
            result.__module__ = _sys._getframe(1).f_globals.get('__name__', '__main__')
 
267
        except (AttributeError, ValueError):
 
268
            pass
 
269
 
 
270
        return result