~duplicity-team/duplicity/0.8-series

« back to all changes in this revision

Viewing changes to duplicity/lazy.py

  • Committer: kenneth at loafman
  • Date: 2018-07-23 16:32:30 UTC
  • Revision ID: kenneth@loafman.com-20180723163230-i226wdy5q2zzgfc7
* Fixed unadorned strings to unicode in duplicity/*/*
  - Some fixup due to shifting indenataion not matching PEP8.
  - Substituted for non-ascii char in jottlibbackend.py comment.

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
# along with duplicity; if not, write to the Free Software Foundation,
20
20
# Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
21
 
22
 
"""Define some lazy data structures and functions acting on them"""
 
22
u"""Define some lazy data structures and functions acting on them"""
23
23
from __future__ import print_function
24
24
 
25
25
import os
29
29
 
30
30
 
31
31
class Iter:
32
 
    """Hold static methods for the manipulation of lazy iterators"""
 
32
    u"""Hold static methods for the manipulation of lazy iterators"""
33
33
 
34
34
    @staticmethod
35
35
    def filter(predicate, iterator):  # @NoSelf
36
 
        """Like filter in a lazy functional programming language"""
 
36
        u"""Like filter in a lazy functional programming language"""
37
37
        for i in iterator:
38
38
            if predicate(i):
39
39
                yield i
40
40
 
41
41
    @staticmethod
42
42
    def map(function, iterator):  # @NoSelf
43
 
        """Like map in a lazy functional programming language"""
 
43
        u"""Like map in a lazy functional programming language"""
44
44
        for i in iterator:
45
45
            yield function(i)
46
46
 
47
47
    @staticmethod
48
48
    def foreach(function, iterator):  # @NoSelf
49
 
        """Run function on each element in iterator"""
 
49
        u"""Run function on each element in iterator"""
50
50
        for i in iterator:
51
51
            function(i)
52
52
 
53
53
    @staticmethod
54
54
    def cat(*iters):  # @NoSelf
55
 
        """Lazily concatenate iterators"""
 
55
        u"""Lazily concatenate iterators"""
56
56
        for iter in iters:
57
57
            for i in iter:
58
58
                yield i
59
59
 
60
60
    @staticmethod
61
61
    def cat2(iter_of_iters):  # @NoSelf
62
 
        """Lazily concatenate iterators, iterated by big iterator"""
 
62
        u"""Lazily concatenate iterators, iterated by big iterator"""
63
63
        for iter in iter_of_iters:
64
64
            for i in iter:
65
65
                yield i
66
66
 
67
67
    @staticmethod
68
68
    def empty(iter):  # @NoSelf
69
 
        """True if iterator has length 0"""
 
69
        u"""True if iterator has length 0"""
70
70
        for i in iter:  # @UnusedVariable
71
71
            return None
72
72
        return 1
73
73
 
74
74
    @staticmethod
75
75
    def equal(iter1, iter2, verbose=None, operator=lambda x, y: x == y):  # @NoSelf
76
 
        """True if iterator 1 has same elements as iterator 2
 
76
        u"""True if iterator 1 has same elements as iterator 2
77
77
 
78
78
        Use equality operator, or == if it is unspecified.
79
79
 
83
83
                i2 = next(iter2)
84
84
            except StopIteration:
85
85
                if verbose:
86
 
                    print("End when i1 = %s" % (i1,))
 
86
                    print(u"End when i1 = %s" % (i1,))
87
87
                return None
88
88
            if not operator(i1, i2):
89
89
                if verbose:
90
 
                    print("%s not equal to %s" % (i1, i2))
 
90
                    print(u"%s not equal to %s" % (i1, i2))
91
91
                return None
92
92
        try:
93
93
            i2 = next(iter2)
94
94
        except StopIteration:
95
95
            return 1
96
96
        if verbose:
97
 
            print("End when i2 = %s" % (i2,))
 
97
            print(u"End when i2 = %s" % (i2,))
98
98
        return None
99
99
 
100
100
    @staticmethod
101
101
    def Or(iter):  # @NoSelf
102
 
        """True if any element in iterator is true.  Short circuiting"""
 
102
        u"""True if any element in iterator is true.  Short circuiting"""
103
103
        i = None
104
104
        for i in iter:
105
105
            if i:
108
108
 
109
109
    @staticmethod
110
110
    def And(iter):  # @NoSelf
111
 
        """True if all elements in iterator are true.  Short circuiting"""
 
111
        u"""True if all elements in iterator are true.  Short circuiting"""
112
112
        i = 1
113
113
        for i in iter:
114
114
            if not i:
117
117
 
118
118
    @staticmethod
119
119
    def len(iter):  # @NoSelf
120
 
        """Return length of iterator"""
 
120
        u"""Return length of iterator"""
121
121
        i = 0
122
122
        while 1:
123
123
            try:
128
128
 
129
129
    @staticmethod
130
130
    def foldr(f, default, iter):  # @NoSelf
131
 
        """foldr the "fundamental list recursion operator"?"""
 
131
        u"""foldr the "fundamental list recursion operator"?"""
132
132
        try:
133
133
            next_item = next(iter)
134
134
        except StopIteration:
137
137
 
138
138
    @staticmethod
139
139
    def foldl(f, default, iter):  # @NoSelf
140
 
        """the fundamental list iteration operator.."""
 
140
        u"""the fundamental list iteration operator.."""
141
141
        while 1:
142
142
            try:
143
143
                next_item = next(iter)
147
147
 
148
148
    @staticmethod
149
149
    def multiplex(iter, num_of_forks, final_func=None, closing_func=None):  # @NoSelf
150
 
        """Split a single iterater into a number of streams
 
150
        u"""Split a single iterater into a number of streams
151
151
 
152
152
        The return val will be a list with length num_of_forks, each
153
153
        of which will be an iterator like iter.  final_func is the
175
175
        called_closing_func = [None]
176
176
 
177
177
        def get_next(fork_num):
178
 
            """Return the next element requested by fork_num"""
 
178
            u"""Return the next element requested by fork_num"""
179
179
            if forkposition[fork_num] == -1:
180
180
                try:
181
181
                    buffer.insert(0, next(iter))
208
208
 
209
209
 
210
210
class IterMultiplex2:
211
 
    """Multiplex an iterator into 2 parts
 
211
    u"""Multiplex an iterator into 2 parts
212
212
 
213
213
    This is a special optimized case of the Iter.multiplex function,
214
214
    used when there is no closing_func or final_func, and we only want
221
221
        self.iter = iter
222
222
 
223
223
    def yielda(self):
224
 
        """Return first iterator"""
 
224
        u"""Return first iterator"""
225
225
        buf, iter = self.buffer, self.iter
226
226
        while(1):
227
227
            if self.a_leading_by >= 0:
235
235
            yield elem
236
236
 
237
237
    def yieldb(self):
238
 
        """Return second iterator"""
 
238
        u"""Return second iterator"""
239
239
        buf, iter = self.buffer, self.iter
240
240
        while(1):
241
241
            if self.a_leading_by <= 0:
250
250
 
251
251
 
252
252
class IterTreeReducer:
253
 
    """Tree style reducer object for iterator - stolen from rdiff-backup
 
253
    u"""Tree style reducer object for iterator - stolen from rdiff-backup
254
254
 
255
255
    The indicies of a RORPIter form a tree type structure.  This class
256
256
    can be used on each element of an iter in sequence and the result
264
264
 
265
265
    """
266
266
    def __init__(self, branch_class, branch_args):
267
 
        """ITR initializer"""
 
267
        u"""ITR initializer"""
268
268
        self.branch_class = branch_class
269
269
        self.branch_args = branch_args
270
270
        self.index = None
272
272
        self.branches = [self.root_branch]
273
273
 
274
274
    def finish_branches(self, index):
275
 
        """Run Finish() on all branches index has passed
 
275
        u"""Run Finish() on all branches index has passed
276
276
 
277
277
        When we pass out of a branch, delete it and process it with
278
278
        the parent.  The innermost branches will be the last in the
295
295
                return 1
296
296
 
297
297
    def add_branch(self):
298
 
        """Return branch of type self.branch_class, add to branch list"""
 
298
        u"""Return branch of type self.branch_class, add to branch list"""
299
299
        branch = self.branch_class(*self.branch_args)
300
300
        self.branches.append(branch)
301
301
        return branch
302
302
 
303
303
    def process_w_branch(self, index, branch, args):
304
 
        """Run start_process on latest branch"""
 
304
        u"""Run start_process on latest branch"""
305
305
        robust.check_common_error(branch.on_error,
306
306
                                  branch.start_process, args)
307
307
        if not branch.caught_exception:
309
309
        branch.base_index = index
310
310
 
311
311
    def Finish(self):
312
 
        """Call at end of sequence to tie everything up"""
 
312
        u"""Call at end of sequence to tie everything up"""
313
313
        while 1:
314
314
            to_be_finished = self.branches.pop()
315
315
            to_be_finished.call_end_proc()
318
318
            self.branches[-1].branch_process(to_be_finished)
319
319
 
320
320
    def __call__(self, *args):
321
 
        """Process args, where args[0] is current position in iterator
 
321
        u"""Process args, where args[0] is current position in iterator
322
322
 
323
323
        Returns true if args successfully processed, false if index is
324
324
        not in the current tree and thus the final result is
335
335
            return 1
336
336
 
337
337
        if index <= self.index:
338
 
            log.Warn(_("Warning: oldindex %s >= newindex %s") %
 
338
            log.Warn(_(u"Warning: oldindex %s >= newindex %s") %
339
339
                     (util.uindex(self.index), util.uindex(index)))
340
340
            return 1
341
341
 
357
357
 
358
358
 
359
359
class ITRBranch:
360
 
    """Helper class for IterTreeReducer above
 
360
    u"""Helper class for IterTreeReducer above
361
361
 
362
362
    There are five stub functions below: start_process, end_process,
363
363
    branch_process, fast_process, and can_fast_process.  A class that
370
370
    caught_exception = start_successful = None
371
371
 
372
372
    def call_end_proc(self):
373
 
        """Runs the end_process on self, checking for errors"""
 
373
        u"""Runs the end_process on self, checking for errors"""
374
374
        if self.finished or not self.start_successful:
375
375
            self.caught_exception = 1
376
376
 
381
381
        self.finished = 1
382
382
 
383
383
    def start_process(self, *args):
384
 
        """Do some initial processing (stub)"""
 
384
        u"""Do some initial processing (stub)"""
385
385
        pass
386
386
 
387
387
    def end_process(self):
388
 
        """Do any final processing before leaving branch (stub)"""
 
388
        u"""Do any final processing before leaving branch (stub)"""
389
389
        pass
390
390
 
391
391
    def branch_process(self, branch):
392
 
        """Process a branch right after it is finished (stub)"""
 
392
        u"""Process a branch right after it is finished (stub)"""
393
393
        assert branch.finished
394
394
        pass
395
395
 
396
396
    def can_fast_process(self, *args):
397
 
        """True if object can be processed without new branch (stub)"""
 
397
        u"""True if object can be processed without new branch (stub)"""
398
398
        return None
399
399
 
400
400
    def fast_process(self, *args):
401
 
        """Process args without new child branch (stub)"""
 
401
        u"""Process args without new child branch (stub)"""
402
402
        pass
403
403
 
404
404
    def on_error(self, exc, *args):
405
 
        """This is run on any exception in start/end-process"""
 
405
        u"""This is run on any exception in start/end-process"""
406
406
        self.caught_exception = 1
407
407
        if args and args[0] and isinstance(args[0], tuple):
408
408
            filename = os.path.join(*args[0])
409
409
        elif self.index:
410
410
            filename = os.path.join(*self.index)  # pylint: disable=not-an-iterable
411
411
        else:
412
 
            filename = "."
413
 
        log.Warn(_("Error '%s' processing %s") % (exc, util.fsdecode(filename)),
 
412
            filename = u"."
 
413
        log.Warn(_(u"Error '%s' processing %s") % (exc, util.fsdecode(filename)),
414
414
                 log.WarningCode.cannot_process,
415
415
                 util.escape(filename))
416
416
 
417
417
    def log_prev_error(self, index):
418
 
        """Call function if no pending exception"""
 
418
        u"""Call function if no pending exception"""
419
419
        if not index:
420
 
            index_str = "."
 
420
            index_str = u"."
421
421
        else:
422
422
            index_str = os.path.join(*index)
423
 
        log.Warn(_("Skipping %s because of previous error") % util.fsdecode(index_str),
 
423
        log.Warn(_(u"Skipping %s because of previous error") % util.fsdecode(index_str),
424
424
                 log.WarningCode.process_skipped,
425
425
                 util.escape(index_str))