File: ziptools/ziptools/README.txt

ziptools - wrap and extend Python's zipfile for common use

Version:  1.0, released June 2017 with the mergeall 3.0 package.
License:  provided freely, but with no warranties of any kind.
Author:   © M. Lutz ( 2017.
Run with: Python 3.X or 2.X, on Windows, Mac OS X, Linux, others.


This package wraps Python's zipfile module for common use cases, and 
extends it with extra features including support for adding folders, 
modtime propagation, symlinks on Unix and Windows, cruft-file handling,
and long Windows paths.  It provides both:

  -Library tools for use in programs (module ziptools/
  -Command-line scripts for general use (the zip-*.py files here)

Both foster flexible and portable content management using zipfiles.


In the following:
  - "py" is your installed Python's name (e.g., "py -3", "python3")
  - "mycontent" and "myunzipdir" may be relative or absolute pathnames
  - "" may be located at a relative or absolute path
  - "/Code" is the folder in which you've unzipped the ziptools package

Command lines:
  $ py /Code/ziptools/ mycontent -skipcruft
        --store all of folder mycontent in new zipfile

  $ py /Code/ziptools/
        --list the contents of zipfile

  $ py /Code/ziptools/ myunzipdir
        --extract the contents of to folder myunzipdir

  $ py /Code/ziptools/ ../ * -skipcruft
        --store folder contents as top-level items, where "*" supported 

Gerenal formats:
  [python] [zipfile source [source...] [-skipcruft] [-atlinks]]
  [python] [zipfile [unzipto] [-nofixlinks]]

Program library:
  $ export PYTHONPATH=/Code/ziptools
  $ py
  >>> import ziptools
  >>> cruftdflt = ziptools.cruft_skip_keep
  >>> ziptools.createzipfile('', ['mycontent'], cruftpatts=cruftdflt)
  >>> ziptools.extractzipfile('', pathto='myunzipdir')

Related tools:
  $ py /Code/mergeall/ mycontent myunzipdir/mycontent -report -skipcruft 
  $ py /Code/mergeall/  mycontent myunzipdir/mycontent -skipcruft
        --verify results, per


Python's standard zipfile module does great low-level work, but this 
package adds both much-needed features and higher-level access points, 
and documents some largely undocumented dark corners of Python's zipfile
along the way.  Among its features, ziptools:

  - Adds entire folder trees to zipfiles automatically 
  - Propagates original modtimes for files, folders, and links
  - Can either include or skip system "cruft" files on request
  - Supports symlinks to files and dirs on Unix and Windows
  - Supports long pathnames on Windows beyond its normal limits 

In brief:

   are added to zipfiles as a whole automatically with extra code,
   a sorely missed feature of Python's standard module

   for all items are propagated to and from zipfiles, another glaring
   omission in Python's standard module.  This is crucial when used 
   with tools that rely on file timestamps (e.g., mergeall).

Cruft-file skipping
   can be used to avoid adding platform-specific metadata files to 
   cross-platform zipfile archives (e.g., ".DS_Store" Finder files 
   on Macs, and "Desktop.ini" files on Windows).  Cruft is identified 
   with either custom skip and keep filename patterns, or a provided 
   general-purpose default.  It can also be omitted or retained as
   desired, via the "-skipcruft" command-line switch and corresponding
   function argument; see and for details.

Symlinks (symbolic links)
   are supported on both Unix and Windows.  By default, links are 
   copied verbatim, but clients may elect to copy referenced items 
   instead with the "-atlinks" switch and argument.  Highlights:

   - When links are copied verbatim, they are by default also made 
     portable between Unix and Windows by automatically adjusting link
     paths for the hosting platform's path separators: simply zip and
     unzip to transport symlinks across platforms.  The "-nofixlinks" 
     switch suppresses this adjustment when required.

   - When links are followed to copy items referenced with "-atlinks",
     recursive links are detected and copied verbatim to avoid loops, 
     on platforms that support inode-like identifiers.  Recursion 
     detection works on all Unix, and Windows Pythons 3.2+.

   See and for more on "-atlinks", and and for more on "-nofixlinks".

Long pathnames on Windows
   are allowed to exceed the normal 260/248-character length limit on 
   that platform, by automatically prefixing paths with '\\?\' as needed
   when they are passed to the underlying Python zipfile module's tools.  

   No user action is required for this fix.  On all versions of Windows,
   it supports files and folders at long Windows paths both when adding 
   to and extracting from zip archives.  Among other things, this is  
   useful for unzipping and rezipping long-path items zipped on Unix.

Beyond its features, this package also provides free command-line zip 
and unzip programs that work portably on Windows, Mac OS X, Linux, and 
more; runs all its code on either Python 3.X or 2.X; and comes with 
complete and changeable Python source code.

See and for more details omitted here, 
and ziptools/ for lower-level implementation details.


ziptools/ is the main utility module, and the zip-*.py console
scripts wrap it for command-line use: creation, extraction, and listing.

All code in this package works under both Python 3.X and 2.X.

The test-case folders here:

  - selftest/
  - cmdtest/
  - moretests/ 

all give example usage and runs, and each script and module in this package
includes in-depth documentation strings with details omitted here for space.
See also mergeall's test/test-symlinks/ for similar symlink support and tests.

In general, items added to zip archives are recorded with the relative or 
absolute paths given, less any leading drive, UNC, and relative-path syntax.  
Items are later unzipped to these paths relative to an unzip target folder.  
See the create and extract scripts' docstrings for more path usage details.

Quick examples by usage mode:

PROGRAM MODE-------------------------------------------------------------------

See ziptools/ for more on program usage.

  import ziptools
  ziptools.createzipfile(zipto, sources)
  ziptools.extractzipfile(zipfrom, unzipto)

  ziptools.createzipfile('', ['test1', 'test2'])
  ziptools.extractzipfile('', '.')

  from ziptools.zipcruft import cruft_skip_keep
  ziptools.createzipfile('', ['website'], cruftpatts=cruft_skip_keep)
  ziptools.extractzipfile('', '~/public_html')

  ziptools.createzipfile('', ['dev'])
  ziptools.extractzipfile('', '.')

  ziptools.extractzipfile('', '.', nofixlinks=True)
  ziptools.createzipfile('', ['skeleton'], atlinks=True)

COMMAND-LINE MODE--------------------------------------------------------------

See and for more on command-line usage.

  # test folders
  c:\...\ziptools> cmdtest\ selftest\test1 selftest\test2
  c:\...\ziptools> cmdtest\
  c:\...\ziptools> cmdtest\ cmdtest\target

  # websites
  ~/webdir$ python3 code/ -skipcruft ~/Desktop/ .
  ~/webdir$ python2 code/ public_html 

  # distributions
  ~/pkgdir$ python3 code/ programdir -skipcruft
  ~/pkgdir$ python3 code/ programdir

  # development
  ....work1$ python $TOOLS/ dev -skipcruft
  ....work2$ python $TOOLS/ . 

  # special cases: populating from links, retaining link separators
  ....work1$ python $TOOLS/ dev -skipcruft -atlinks
  ....work2$ python $TOOLS/ . -nofixlinks

  # shell pattern expansion (in shells that support it: Unix, etc.)$ python $TOOLS/$ python $TOOLS/ *.py 

  # use items in a folder as top-level items, not nested in their folder
  cd sourcedir$ python $TOOLS/ ../ * -skipcruft 
  cd destdir, copy$ python $TOOLS/ . 

INTERACTIVE MODE---------------------------------------------------------------

In the following, substitute "\" for all "/" when working on Windows.

  # EXTRACT an existing zipfile to ".", the current directory

  .../test-symlinks$ ...ziptools/
  Zip file to extract?
  Folder to extract in (use . for here) ? .
  Do not localize symlinks (y=yes)? 
  About to UNZIP,
	to .,
	localizing any links
  Confirm with 'y'? y
  Clean target folder first (yes=y)? n
  Unzipping from to .
  Extracted test1/
		=> test1

  # CREATE a new zipfile in a folder, from items in a folder

  Zip file to create? cmdtest/ziptest
  Items to zip (comma-separated)? selftest/test1,selftest/test2                   
  Skip cruft items (y=yes)? y
  Follow links to targets (y=yes)? n
  About to ZIP
	['selftest/test1', 'selftest/test2'],
	to cmdtest/,
	skipping cruft,
	not following links
  Confirm with 'y'? y
  Zipping ['selftest/test1', 'selftest/test2'] to cmdtest/
  Cruft patterns: {'skip': ['.*', '[dD]esktop.ini', 'Thumbs.db', '~*', '$*', '*.py[co]'], 'keep': ['.htaccess']}
  Adding folder selftest/test1
  --Skipped cruft file selftest/test1/.DS_Store

  # EXTRACT the zipfile just created, to another folder

  ../ziptools$ py3 
  Zip file to extract? cmdtest/ziptest
  Folder to extract in (use . for here) ? cmdtest/target
  Do not localize symlinks (y=yes)? 
  About to UNZIP
	to cmdtest/target,
	localizing any links
  Confirm with 'y'? y
  Clean target folder first (yes=y)? y
  Removing cmdtest/target/selftest
  Unzipping from cmdtest/ to cmdtest/target
  Extracted selftest/test1/
		=> cmdtest/target/selftest/test1

  # LIST the created zipfile's contents

  Zipfile to list? cmdtest/
  File Name                                             Modified             Size
  selftest/test1/                                2016-10-02 09:01:58            0
  selftest/test1/d1/                             2016-09-30 16:41:12            0
  selftest/test1/d1/fa1.txt                      2014-02-07 16:38:58            0
  selftest/test1/d3/                             2016-10-02 09:05:02            0
  selftest/test1/d3/.htaccess                    2015-03-31 16:55:44          271

  # EXTRACT using absolute paths, on Unix and Windows

  /...$ py3 /Code/ziptools/ 
  Zip file to extract? /Users/blue/Desktop/
  Folder to extract in (use . for here) ? /Users/blue/Desktop/temp/website
  Do not localize symlinks (y=yes)? n
  About to UNZIP
	to /Users/blue/Desktop/temp/website,
	localizing any links
  Confirm with 'y'? y

  c:\...> py -3 C:\Code\ziptools\ 
  Zip file to extract? C:\Users\me\Desktop\
  Folder to extract in (use . for here) ? C:\Users\me\Desktop\temp\website
  Do not localize symlinks (y=yes)? n
  About to UNZIP
          to C:\Users\me\Desktop\temp\website,
          localizing any links
  Confirm with 'y'? y

[Home] Books Programs Blog Python Author Training Search Email ©M.Lutz