Test Failed
Branch master (c56792)
by John
02:11
created

bbarchivist.archiveutils   F

Complexity

Total Complexity 96

Size/Duplication

Total Lines 716
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 233
dl 0
loc 716
rs 1.263
c 0
b 0
f 0
ccs 215
cts 215
cp 1
wmc 96

41 Functions

Rating   Name   Duplication   Size   Complexity  
A filter_without_boolfilt() 0 14 3
A pack_tclloader() 0 15 2
A filter_with_boolfilt() 0 14 3
A tar_verify() 0 8 1
A pack_tclloader_sz() 0 15 1
A filter_method_nosz() 0 17 4
A tgz_compress() 0 15 1
A verify_android_tools() 0 10 4
A pack_tclloader_zip() 0 19 4
A compressfilter() 0 15 4
A filter_method() 0 14 3
A smart_is_tarfile() 0 13 3
A zip_verify() 0 13 3
A generic_tarfile_verify() 0 17 4
A tarzip_verifier() 0 13 3
A compress_config_loader() 0 12 3
A txz_compress() 0 15 2
A zip_compress() 0 14 2
A szcodes() 0 13 1
A sz_subprocess() 0 10 2
B sz_compress() 0 29 2
A tar_compress() 0 12 1
A generic_nocompresslevel() 0 15 2
A filtercomp() 0 19 2
A prep_compress_function() 0 21 4
A tgz_verify() 0 8 1
A decide_verifier_printer() 0 14 2
A decide_verifier() 0 17 3
A sz_verify() 0 14 1
A generic_compresslevel() 0 18 2
A compress_config_writer() 0 13 2
B compressfilter_select() 0 24 4
A txz_verify() 0 12 2
B compress() 0 29 2
A tbz_compress() 0 15 1
A generic_tarfile_compress() 0 21 2
A calculate_strength() 0 6 2
A verify() 0 20 2
A extract_zip() 0 12 1
A extract_android_tools() 0 13 4
A tbz_verify() 0 8 1

How to fix   Complexity   

Complexity

Complex classes like bbarchivist.archiveutils often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
#!/usr/bin/env python3
2 5
"""This module is used to operate with archives."""
3
4 5
import os  # filesystem read
5 5
import subprocess  # invocation of 7z, cap
6 5
import tarfile  # txz/tbz/tgz/tar compression
7 5
import zipfile  # zip compresssion
8
9 5
from bbarchivist import barutils  # zip tester
10 5
from bbarchivist import bbconstants  # premade stuff
11 5
from bbarchivist import decorators  # timer
12 5
from bbarchivist import iniconfig  # config parsing
13 5
from bbarchivist import utilities  # platform determination
14
15 5
__author__ = "Thurask"
16 5
__license__ = "WTFPL v2"
17 5
__copyright__ = "2015-2018 Thurask"
18
19
20 5
def smart_is_tarfile(filepath):
21
    """
22
    :func:`tarfile.is_tarfile` plus error handling.
23
24
    :param filepath: Filename.
25
    :type filepath: str
26
    """
27 5
    try:
28 5
        istar = tarfile.is_tarfile(filepath)
29 5
    except (OSError, IOError):
30 5
        return False
31
    else:
32 5
        return istar
33
34
35 5
def szcodes():
36
    """
37
    Return dictionary of 7-Zip error codes.
38
    """
39 5
    szc = {
40
        0: "NO ERRORS",
41
        1: "COMPLETED WITH WARNINGS",
42
        2: "FATAL ERROR",
43
        7: "COMMAND LINE ERROR",
44
        8: "OUT OF MEMORY ERROR",
45
        255: "USER STOPPED PROCESS"
46
    }
47 5
    return szc
48
49
50 5
@decorators.timer
51 5
def sz_compress(filepath, filename, szexe=None, strength=5, errors=False):
52
    """
53
    Pack a file into a LZMA2 7z file.
54
55
    :param filepath: Basename of file, no extension.
56
    :type filepath: str
57
58
    :param filename: Name of file to pack.
59
    :type filename: str
60
61
    :param szexe: Path to 7z executable.
62
    :type szexe: str
63
64
    :param strength: Compression strength. 5 is normal, 9 is ultra.
65
    :type strength: int
66
67
    :param errors: Print completion status message. Default is false.
68
    :type errors: bool
69
    """
70 5
    strength = str(strength)
71 5
    szc = szcodes()
72 5
    rawname = os.path.dirname(filepath)
73 5
    thr = str(utilities.get_core_count())
74 5
    fold = os.path.join(rawname, filename)
75 5
    cmd = '{0} a -mx{1} -m0=lzma2 -mmt{2} "{3}.7z" "{4}"'.format(szexe, strength, thr, filepath, fold)
76 5
    excode = sz_subprocess(cmd)
77 5
    if errors:
78 5
        print(szc[excode])
79
80
81 5
def sz_subprocess(cmd):
82
    """
83
    Subprocess wrapper for 7-Zip commands.
84
85
    :param cmd: Command to pass to subprocess.
86
    :type cmd: str
87
    """
88 5
    with open(os.devnull, 'wb') as dnull:
89 5
        output = subprocess.call(cmd, stdout=dnull, stderr=subprocess.STDOUT, shell=True)
90 5
    return output
91
92
93 5
def sz_verify(filepath, szexe=None):
94
    """
95
    Verify that a .7z file is valid and working.
96
97
    :param filepath: Filename.
98
    :type filepath: str
99
100
    :param szexe: Path to 7z executable.
101
    :type szexe: str
102
    """
103 5
    filepath = os.path.abspath(filepath)
104 5
    cmd = '{0} t "{1}"'.format(szexe, filepath)
105 5
    excode = sz_subprocess(cmd)
106 5
    return excode == 0
107
108
109 5
def generic_tarfile_verify(filepath, method):
110
    """
111
    Verify that a tar/tgz/tbz/txz file is valid and working.
112
113
    :param filepath: Filename.
114
    :type filepath: str
115
116
    :param method: Tarfile read method.
117
    :type method: str
118
    """
119 5
    if smart_is_tarfile(filepath):
120 5
        with tarfile.open(filepath, method) as thefile:
121 5
            mems = thefile.getmembers()
122 5
        sentinel = False if not mems else True
123
    else:
124 5
        sentinel = False
125
    return sentinel
126
127 5
128
def generic_tarfile_compress(archivename, filename, method, strength=5):
129
    """
130
    Pack a file into an uncompressed/gzip/bzip2/LZMA tarfile.
131
132
    :param archivename: Archive name.
133
    :type archivename: str
134
135
    :param filename: Name of file to pack into archive.
136
    :type filename: str
137
138
    :param method: Tarfile compress method.
139
    :type method: str
140
141
    :param strength: Compression strength. 5 is normal, 9 is ultra.
142
    :type strength: int
143 5
    """
144 5
    nocomp = ["w:", "w:xz"]  # methods w/o compression: tar, tar.xz
145 5
    if method in nocomp:
146
        generic_nocompresslevel(archivename, filename, method)
147 5
    else:
148
        generic_compresslevel(archivename, filename, method, strength)
149
150 5
151
def generic_compresslevel(archivename, filename, method, strength=5):
152
    """
153
    Pack a file into a gzip/bzip2 tarfile.
154
155
    :param archivename: Archive name.
156
    :type archivename: str
157
158
    :param filename: Name of file to pack into archive.
159
    :type filename: str
160
161
    :param method: Tarfile compress method.
162
    :type method: str
163
164
    :param strength: Compression strength. 5 is normal, 9 is ultra.
165
    :type strength: int
166 5
    """
167 5
    with tarfile.open(archivename, method, compresslevel=strength) as afile:
168
        afile.add(filename, filter=None, arcname=os.path.basename(filename))
169
170 5
171
def generic_nocompresslevel(archivename, filename, method):
172
    """
173
    Pack a file into an uncompressed/LZMA tarfile.
174
175
    :param archivename: Archive name.
176
    :type archivename: str
177
178
    :param filename: Name of file to pack into archive.
179
    :type filename: str
180
181
    :param method: Tarfile compress method.
182
    :type method: str
183 5
    """
184 5
    with tarfile.open(archivename, method) as afile:
185
        afile.add(filename, filter=None, arcname=os.path.basename(filename))
186
187 5
188
@decorators.timer
189
def tar_compress(filepath, filename):
190
    """
191
    Pack a file into an uncompressed tarfile.
192
193
    :param filepath: Basename of file, no extension.
194
    :type filepath: str
195
196
    :param filename: Name of file to pack.
197
    :type filename: str
198 5
    """
199
    generic_tarfile_compress("{0}.tar".format(filepath), filename, "w:")
200
201 5
202
def tar_verify(filepath):
203
    """
204
    Verify that a tar file is valid and working.
205
206
    :param filepath: Filename.
207
    :type filepath: str
208 5
    """
209
    return generic_tarfile_verify(filepath, "r:")
210
211 5
212 5
@decorators.timer
213
def tgz_compress(filepath, filename, strength=5):
214
    """
215
    Pack a file into a gzip tarfile.
216
217
    :param filepath: Basename of file, no extension.
218
    :type filepath: str
219
220
    :param filename: Name of file to pack.
221
    :type filename: str
222
223
    :param strength: Compression strength. 5 is normal, 9 is ultra.
224
    :type strength: int
225 5
    """
226
    generic_tarfile_compress("{0}.tar.gz".format(filepath), filename, "w:gz", strength)
227
228 5
229
def tgz_verify(filepath):
230
    """
231
    Verify that a tar.gz file is valid and working.
232
233
    :param filepath: Filename.
234
    :type filepath: str
235 5
    """
236
    return generic_tarfile_verify(filepath, "r:gz")
237
238 5
239 5
@decorators.timer
240
def tbz_compress(filepath, filename, strength=5):
241
    """
242
    Pack a file into a bzip2 tarfile.
243
244
    :param filepath: Basename of file, no extension.
245
    :type filepath: str
246
247
    :param filename: Name of file to pack.
248
    :type filename: str
249
250
    :param strength: Compression strength. 5 is normal, 9 is ultra.
251
    :type strength: int
252 5
    """
253
    generic_tarfile_compress("{0}.tar.bz2".format(filepath), filename, "w:bz2", strength)
254
255 5
256
def tbz_verify(filepath):
257
    """
258
    Verify that a tar.bz2 file is valid and working.
259
260
    :param filepath: Filename.
261
    :type filepath: str
262 5
    """
263
    return generic_tarfile_verify(filepath, "r:bz2")
264
265 5
266
@decorators.timer
267
def txz_compress(filepath, filename):
268
    """
269
    Pack a file into a LZMA tarfile.
270
271
    :param filepath: Basename of file, no extension.
272
    :type filepath: str
273
274
    :param filename: Name of file to pack.
275
    :type filename: str
276 5
    """
277 5
    if not utilities.new_enough(3):
278
        pass
279 4
    else:
280
        generic_tarfile_compress("{0}.tar.xz".format(filepath), filename, "w:xz")
281
282 5
283
def txz_verify(filepath):
284
    """
285
    Verify that a tar.xz file is valid and working.
286
287
    :param filepath: Filename.
288
    :type filepath: str
289 5
    """
290 5
    if not utilities.new_enough(3):
291
        sentinel = None
292 4
    else:
293
        sentinel = generic_tarfile_verify(filepath, "r:xz")
294
    return sentinel
295 5
296
297
@decorators.timer
298
def zip_compress(filepath, filename):
299
    """
300
    Pack a file into a DEFLATE zipfile.
301
302
    :param filepath: Basename of file, no extension.
303
    :type filepath: str
304
305
    :param filename: Name of file to pack.
306 5
    :type filename: str
307 5
    """
308
    zipf = "{0}.zip".format(filepath)
309
    with zipfile.ZipFile(zipf, 'w', zipfile.ZIP_DEFLATED, allowZip64=True) as zfile:
310 5
        zfile.write(filename, arcname=os.path.basename(filename))
311
312
313
def zip_verify(filepath):
314
    """
315
    Verify that a .zip file is valid and working.
316
317 5
    :param filepath: Filename.
318 5
    :type filepath: str
319 5
    """
320
    if zipfile.is_zipfile(filepath):
321 5
        brokens = barutils.bar_tester(filepath)
322
        sentinel = True if brokens != filepath else False
323
    else:
324 5
        sentinel = False
325
    return sentinel
326
327
328
def filter_method(method, szexe=None):
329
    """
330
    Make sure methods are OK.
331
332
    :param method: Compression method to use.
333
    :type method: str
334 5
335 5
    :param szexe: Path to 7z executable, if needed.
336 5
    :type szexe: str
337 5
    """
338
    if not utilities.new_enough(3) and method == "txz":
339
        method = "zip"  # fallback
340 5
    method = filter_method_nosz(method, szexe)
341
    return method
342
343
344
def filter_method_nosz(method, szexe=None):
345
    """
346
    Make sure 7-Zip is OK.
347
348
    :param method: Compression method to use.
349
    :type method: str
350 5
351 5
    :param szexe: Path to 7z executable, if needed.
352 5
    :type szexe: str
353 5
    """
354
    if method == "7z" and szexe is None:
355 5
        ifexists = utilities.prep_seven_zip()  # see if 7z exists
356 5
        if not ifexists:
357
            method = "zip"  # fallback
358
        else:
359 5
            szexe = utilities.get_seven_zip(False)
360
    return method
361
362
363 5
def calculate_strength():
364 5
    """
365
    Determine zip/gzip/bzip2 strength by OS bit setting.
366
    """
367 5
    strength = 9 if utilities.is_amd64() else 5
368
    return strength
369
370
371
def filter_with_boolfilt(files, criterion, critargs):
372
    """
373
    Return everything that matches criterion.
374
375
    :param files: Files to work on.
376
    :type files: list(str)
377
378
    :param criterion: Function to use for evaluation.
379
    :type criterion: func
380 5
381
    :param critargs: Arguments for function, other than file.
382
    :type critargs: list
383 5
    """
384
    return [file for file in files if criterion(file, *critargs)]
385
386
387
def filter_without_boolfilt(files, criterion, critargs):
388
    """
389
    Return everything that doesn't match criterion.
390
391
    :param files: Files to work on.
392
    :type files: list(str)
393
394
    :param criterion: Function to use for evaluation.
395
    :type criterion: func
396 5
397
    :param critargs: Arguments for function, other than file.
398
    :type critargs: list
399 5
    """
400
    return [file for file in files if not criterion(file, *critargs)]
401
402
403
def filtercomp(files, criterion, critargs, boolfilt=True):
404
    """
405
    :param files: Files to work on.
406
    :type files: list(str)
407
408
    :param criterion: Function to use for evaluation.
409
    :type criterion: func
410
411
    :param critargs: Arguments for function, other than file.
412
    :type critargs: list
413 5
414 5
    :param boolfilt: True if comparing criterion, False if comparing not criterion.
415
    :type boolfilt: bool
416 5
    """
417 5
    if boolfilt:
418
        fx2 = filter_with_boolfilt(files, criterion, critargs)
419
    else:
420 5
        fx2 = filter_without_boolfilt(files, criterion, critargs)
421
    return fx2
422
423
424
def compressfilter_select(filepath, files, selective=False):
425
    """
426
    :param filepath: Working directory. Required.
427
    :type filepath: str
428
429
    :param files: List of files in filepath.
430
    :type files: list(str)
431 5
432 5
    :param selective: Only compress autoloaders. Default is false.
433 5
    :type selective: bool/str
434 5
    """
435 5
    arx = bbconstants.ARCS
436 5
    pfx = bbconstants.PREFIXES
437 5
    if selective is None:
438 5
        filt2 = os.listdir(filepath)
439 5
    elif selective == "arcsonly":
440 5
        filt2 = filtercomp(files, utilities.prepends, ("", arx))
441
    elif selective:
442 5
        filt0 = filtercomp(files, utilities.prepends, (pfx, ""))
443 5
        filt1 = filtercomp(filt0, utilities.prepends, ("", arx), False)  # pop archives
444
        filt2 = filtercomp(filt1, utilities.prepends, ("", ".exe"))  # include exes
445
    else:
446 5
        filt2 = filtercomp(files, utilities.prepends, ("", arx), False)  # pop archives
447
    return filt2
448
449
450
def compressfilter(filepath, selective=False):
451
    """
452
    Filter directory listing of working directory.
453
454
    :param filepath: Working directory. Required.
455
    :type filepath: str
456
457 5
    :param selective: Only compress autoloaders. Default is false.
458 5
    :type selective: bool/str
459 5
    """
460 5
461
    files = [file for file in os.listdir(filepath) if not os.path.isdir(file)]
462
    filt2 = compressfilter_select(filepath, files, selective)
463 5
    filt3 = [os.path.join(filepath, file) for file in filt2]
464
    return filt3
465
466
467
def prep_compress_function(method="7z", szexe=None, errors=False):
468
    """
469
    Prepare compression function and partial arguments.
470
471
    :param method: Compression type. Default is "7z".
472
    :type method: str
473
474
    :param szexe: Path to 7z executable, if needed.
475
    :type szexe: str
476 5
477
    :param errors: Print completion status message. Default is false.
478 5
    :type errors: bool
479 5
    """
480 5
    methods = {"7z": sz_compress, "tgz": tgz_compress, "txz": txz_compress, "tbz": tbz_compress,
481 5
               "tar": tar_compress, "zip": zip_compress}
482 5
    args = [szexe] if method == "7z" else []
483 5
    if method in ("7z", "tbz", "tgz"):
484
        args.append(calculate_strength())
485
    if method == "7z":
486 5
        args.append(errors)
487
    return methods[method], args
488
489
490
def compress(filepath, method="7z", szexe=None, selective=False, errors=False):
491
    """
492
    Compress all autoloader files in a given folder, with a given method.
493
494
    :param filepath: Working directory. Required.
495
    :type filepath: str
496
497
    :param method: Compression type. Default is "7z".
498
    :type method: str
499
500
    :param szexe: Path to 7z executable, if needed.
501
    :type szexe: str
502
503
    :param selective: Only compress autoloaders. Default is false.
504
    :type selective: bool
505 5
506 5
    :param errors: Print completion status message. Default is false.
507 5
    :type errors: bool
508 5
    """
509 5
    method = filter_method(method, szexe)
510 5
    files = compressfilter(filepath, selective)
511 5
    for file in files:
512 5
        fname = os.path.basename(file)
513 5
        filename = os.path.splitext(fname)[0]
514 5
        fileloc = os.path.join(filepath, filename)
515
        print("COMPRESSING: {0}".format(fname))
516
        compfunc, extargs = prep_compress_function(method, szexe, errors)
517 5
        compfunc(fileloc, file, *extargs)
518
    return True
519
520
521
def tarzip_verifier(file):
522
    """
523
    Assign .tar.xxx, .tar and .zip verifiers.
524 5
525
    :param file: Filename.
526
    :type file: str
527 5
    """
528 5
    maps = {".tar.gz": tgz_verify, ".tar.xz": txz_verify,
529 5
            ".tar.bz2": tbz_verify, ".tar": tar_verify,
530
            ".zip": zip_verify, ".bar": zip_verify}
531
    for key, value in maps.items():
532 5
        if file.endswith(key):
533
            return value(file)
534
535
536
def decide_verifier(file, szexe=None):
537
    """
538
    Decide which verifier function to use.
539
540
    :param file: Filename.
541
    :type file: str
542 5
543 5
    :param szexe: Path to 7z executable, if needed.
544 5
    :type szexe: str
545
    """
546 5
    print("VERIFYING: {0}".format(file))
547 5
    if file.endswith(".7z") and szexe is not None:
548 5
        verif = sz_verify(os.path.abspath(file), szexe)
549
    else:
550
        verif = tarzip_verifier(file)
551 5
    decide_verifier_printer(file, verif)
552
    return verif
553
554
555
def decide_verifier_printer(file, verif):
556
    """
557
    Print status of verifier function.
558
559
    :param file: Filename.
560
    :type file: str
561 5
562 5
    :param verif: If the file is OK or not.
563
    :type verif: bool
564 5
    """
565
    if not verif:
566
        print("{0} IS BROKEN!".format(os.path.basename(file)))
567 5
    else:
568
        print("{0} OK".format(os.path.basename(file)))
569
570
571
def verify(filepath, method="7z", szexe=None, selective=False):
572
    """
573
    Verify specific archive files in a given folder.
574
575
    :param filepath: Working directory. Required.
576
    :type filepath: str
577
578
    :param method: Compression type. Default is "7z". Defined in source.
579
    :type method: str
580
581
    :param szexe: Path to 7z executable, if needed.
582
    :type szexe: str
583 5
584 5
    :param selective: Only verify autoloaders. Default is false.
585 5
    :type selective: bool
586 5
    """
587
    method = filter_method(method, szexe)
588
    files = compressfilter(filepath, selective)
589 5
    for file in files:
590
        decide_verifier(file, szexe)
591
592
593
def compress_config_loader(homepath=None):
594
    """
595
    Read a ConfigParser file to get compression preferences.
596 5
597 5
    :param homepath: Folder containing ini file. Default is user directory.
598 5
    :type homepath: str
599 5
    """
600 5
    compini = iniconfig.generic_loader('compression', homepath)
601
    method = compini.get('method', fallback="7z")
602
    if not utilities.new_enough(3) and method == "txz":
603 5
        method = "zip"  # for 3.2 compatibility
604
    return method
605
606
607
def compress_config_writer(method=None, homepath=None):
608
    """
609
    Write a ConfigParser file to store compression preferences.
610
611
    :param method: Method to use.
612
    :type method: str
613 5
614 5
    :param homepath: Folder containing ini file. Default is user directory.
615 5
    :type homepath: str
616
    """
617
    method = compress_config_loader() if method is None else method
618 5
    results = {"method": method}
619
    iniconfig.generic_writer("compression", results, homepath)
620
621
622
def verify_android_tools(tooldir):
623
    """
624
    Verify Android SDK platform tools archives.
625 5
626 5
    :param tooldir: Directory containing platform tools zips.
627 5
    :type tooldir: str
628
    """
629 5
    zipver = [zip_verify(os.path.join(os.path.abspath(tooldir), x)) for x in os.listdir(os.path.abspath(tooldir)) if x.endswith(".zip")]
630
    sentinel = True if zipver == [True, True, True] else False  # all OK
631
    return sentinel
632 5
633
634
def extract_zip(infile, outpath):
635
    """
636
    Extract a zip file to a given output path.
637
638
    :param infile: Path to input zip file.
639
    :type infile: str
640
641
    :param outpath: Path to extract input zip to.
642 5
    :type outpath: str
643 5
    """
644
    zipf = zipfile.ZipFile(infile)
645
    zipf.extractall(outpath)
646 5
647
648
def extract_android_tools(tooldir):
649
    """
650
    Extract Android SDK platform tools archives.
651
652
    :param tooldir: Directory containing platform tools zips.
653 5
    :type tooldir: str
654 5
    """
655 5
    plats = [x for x in os.listdir(os.path.abspath(tooldir)) if x.endswith(".zip")]
656 5
    for zipx in plats:
657 5
        platform = os.path.basename(zipx).replace("platform-tools-latest-", "").replace(".zip", "")
658 5
        platdir = os.path.join(os.path.abspath(tooldir), platform)
659
        os.makedirs(platdir)
660
        extract_zip(os.path.join(os.path.abspath(tooldir), zipx), platdir)
661 5
662
663
@decorators.timer
664
def pack_tclloader(dirname, filename):
665
    """
666
    Compress Android autoloader folder.
667
668
    :param dirname: Target folder.
669
    :type dirname: str
670
671
    :param filename: File title, without extension.
672 5
    :type filename: str
673 5
    """
674
    if utilities.prep_seven_zip():
675 5
        pack_tclloader_sz(dirname, filename)
676
    else:
677
        pack_tclloader_zip(dirname, filename)
678 5
679
680
def pack_tclloader_sz(dirname, filename):
681
    """
682
    Compress Android autoloader folder into a 7z file.
683
684
    :param dirname: Target folder.
685
    :type dirname: str
686
687
    :param filename: File title, without extension.
688 5
    :type filename: str
689 5
    """
690 5
    szexe = utilities.get_seven_zip()
691 5
    strength = calculate_strength()
692 5
    thr = str(utilities.get_core_count())
693
    cmd = '{0} a -mx{1} -m0=lzma2 -mmt{2} "{3}.7z" "./{4}/*"'.format(szexe, strength, thr, filename, dirname)
694
    sz_subprocess(cmd)
695 5
696
697
def pack_tclloader_zip(dirname, filename):
698
    """
699
    Compress Android autoloader folder into a zip file.
700
701
    :param dirname: Target folder.
702
    :type dirname: str
703
704
    :param filename: File title, without extension.
705 5
    :type filename: str
706 5
    """
707 5
    zipf = "{0}.zip".format(filename)
708 5
    with zipfile.ZipFile(zipf, 'w', zipfile.ZIP_DEFLATED, allowZip64=True) as zfile:
709 5
        for root, dirs, files in os.walk(dirname):
710 5
            del dirs
711 5
            for file in files:
712 5
                print("ZIPPING: {0}".format(utilities.stripper(file)))
713
                abs_filename = os.path.join(root, file)
714
                abs_arcname = abs_filename.replace("{0}{1}".format(dirname, os.sep), "")
715
                zfile.write(abs_filename, abs_arcname)
716