Zip File Script & if __name__ == '__main__':

2550
17
Jump to solution
11-17-2016 01:45 PM
JaredPilbeam1
Occasional Contributor
#11/17/2016
#
#take all of the shapefiles in a directory and compress them into individual zip files
#
#########################################################################################

#import workspace

import arcpy, os
from arcpy import env
from os import path as p
import RemoveAddLayer
import zipfile
arcpy.overwriteOutput = True


def ZipShapes(path, outpath):
    arcpy.env.workspace = path
    shapes = arcpy.ListFeatureClasses()

#iterate through list of shapefiles
    for shape in shapes:
        name = p.splitext(shape)[0]
        print name
        zip_path = p.join(out_path, name + '.zip')
        zip = zipfile.ZipFile(zip_path, 'w', compression=zipfile.ZIP_DEFLATED)
        zip.write(p.join(path,shape), shape)
        for f in arcpy.ListFiles('%s*' %name):
            if not f.endswith('.shp'):
                zip.write(p.join(path,f),f)
        print 'All file written to %s' %zip_path
        zip.close()


if __name__ == '__main__':

    path = r"Z:\Jared\Python Scripts"
    outpath = r"W:\Data"

    ZipShapes(path, outpath)
        ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

Only a novice at Python. Using ArcMap for Desktop 10.3. My ultimate objective is to send some shapefiles to a zip file using script. I ran the above based on someone's existing script.

1.) What is if __name__ == '__main__': doing in this scenario?

      From what I understand you can use this when importing another Python script? That's why I have the       "RemoveAddLayer" script as an import at the top. I may be completely wrong?

2.) The RemoveAddLayer script (that's imported at the top) is what I created to update Streets and Address Points layers. Should I save these to a folder in the script and then set that as the path variable in the ZipFiles2 script?

There was no error when I ran this but also no file was put into the outpath folder. 

Edit: @Rebecca: Thanks, I took your advice and put the script in instead of the image. 

0 Kudos
1 Solution

Accepted Solutions
DarrenWiens2
MVP Honored Contributor

I'll probably not get this 100% technically correct, but here goes:

Each script is blessed with a '__name__'. If the script is the main executing file, it gets the name '__main__'. You can also import any .py file as a module, like you did with RemoveAddLayer. When the code executes within RemoveAddLayer, I assume __name__ = 'RemoveAddLayer', or something similar, but definitely not '__main__'.

On the flipside, if you ran a different script that imported the script you've posted above, __name__ != __main__, so that part wouldn't execute. You would still have access to the ZipShapes() function in the first script, though. Clear as mud?

edit: there is lots and lots written out there. Search for '__main__' or '__name__'.

View solution in original post

17 Replies
RebeccaStrauch__GISP
MVP Esteemed Contributor

sorry...not answering your questions righ now, but I noticed one thing that will cause an issue.   you will need an

import zipfile  

in the first script shown.

When asking for help, always best to format the program instead of having images. at the top of the editor window  

... More ... Syntax highlighter -> Python

then copy in you scripts. Also including the software version  is helpful, and any error codes when you are test the code.

BTW, I have a couple versions for zipping, I'll include both below...one is commented out.  both were working, but the second one worked better for me.

import arcpy
import os
def myMsgs(message):
  arcpy.AddMessage("{0}".format(message))
  print("{0}".format(message)  )

'''
# other option for zipping, but other zipws function is working well.
import sys, zipfile
def zip(src, toZip):
  #zf = zipfile.ZipFile("%s.zip" % (dst), "a", zipfile.ZIP_DEFLATED)
  zf = zipfile.ZipFile("{0}a.zip".format(os.path.join(path,toZip)), "a", zipfile.ZIP_DEFLATED)
  abs_src = os.path.abspath(src)
  for dirname, subdirs, files in os.walk(src):
    for filename in files:
      absname = os.path.abspath(os.path.join(dirname, filename))
      arcname = absname[len(abs_src) + 1:]
      #print 'zipping %s as %s' % (os.path.join(dirname, filename), arcname)
      myMsgs('zipping {0} as {1}'.format(filename, arcname))
      zf.write(absname, arcname)
  zf.close()'''

#**********************************************************************
# Import sys and zipfile modules for zip function
# Paramaeters:
#   path: folder to os.walk thru...ignores .lock and other .zip files
#   toZip: file to write
#   fcbase:  filter for files to zip
# keep = False -hardcoded..True puts files in "path folder", False at root of .zip
#**********************************************************************
import sys, zipfile
#keep = False   # keep = True puts files in "path folder", False puts files at root of .zip
def zipws(path, toZip, fcBase, keep=False):
  #zf = zipfile.ZipFile("%s.zip" % (toZip), "w", zipfile.ZIP_DEFLATED)
  zf = zipfile.ZipFile("{0}.zip".format(os.path.join(toZip, fcBase)), "a", zipfile.ZIP_DEFLATED)
  path = os.path.normpath(path)
  # os.walk visits every subdirectory, returning a 3-tuple
  #  of directory name, subdirectories in it, and file names
  #  in it.
  #
  for (dirpath, dirnames, filenames) in os.walk(path):
    # Iterate over every file name #
    for file in filenames:
      # Ignore .lock files and other .zip files#
      if fcBase in file and not file.endswith('.lock') and not file.endswith('.zip'):
        myMsgs("        Adding {0}...".format(os.path.join(path, dirpath, file)))
        try:
          if keep:
            zf.write(os.path.join(dirpath, file),
                     os.path.join(os.path.basename(path), os.path.join(dirpath, file)[len(path)+len(os.sep):]))
          else:
            zf.write(os.path.join(dirpath, file),            
                     os.path.join(dirpath[len(path):], file)) 

        except Exception, e:
          arcpy.AddWarning("    Error adding {0}: {1}".format(file, e))

  return None
#**********************************************************************
# end of function zipws 
#**********************************************************************
JaredPilbeam1
Occasional Contributor

Rebecca,

Might be glaringly obvious, but where did you set your variables in the second script?

0 Kudos
RebeccaStrauch__GISP
MVP Esteemed Contributor

Lol. Not glaringly obvious.  That was just a snippet of the two functions I had found that worked for me.  This us part of a larger script/tool.  I'm not at a place I can access the full script right (on iPad) now so can't show where I set the variable s (might be able to get later if really helpful for you).  The reason I went with the second option is because it had the option of putting all my (shape) files at the root level, versus having a folder within the zip with the files.  For my needs, I did not want the extra layer ( but in some cases it would be nice, I guess).  These are scripts I  found in the web, with maybe minir tweaks for my needs. 

0 Kudos
DarrenWiens2
MVP Honored Contributor

I'll probably not get this 100% technically correct, but here goes:

Each script is blessed with a '__name__'. If the script is the main executing file, it gets the name '__main__'. You can also import any .py file as a module, like you did with RemoveAddLayer. When the code executes within RemoveAddLayer, I assume __name__ = 'RemoveAddLayer', or something similar, but definitely not '__main__'.

On the flipside, if you ran a different script that imported the script you've posted above, __name__ != __main__, so that part wouldn't execute. You would still have access to the ZipShapes() function in the first script, though. Clear as mud?

edit: there is lots and lots written out there. Search for '__main__' or '__name__'.

DanPatterson_Retired
MVP Esteemed Contributor

assuming Rebecca's edits are good-to-go, the 'if __name__.... section is designed to be used if the script is run as a standalone script, not when it is imported.  

That script, if checked and run, would have looked in the Jared folder for stuff to compress and output it the the W folder by running the Zip... def passing the two parameters to it.  If the script were imported, then the def could be used but you would have to provide your own parameters to it for it to run.

To be official here are the docs 29.4. __main__ — Top-level script environment — Python 3.5.2 documentation 

in that example the function main() would run if the script were run as a script, but not if imported.  It doesn't need to be a function called main, it is a convention which I often break  

See the recent poll

EDIT

  I gave some examples in there

JaredPilbeam1
Occasional Contributor
#11/17/2016
#
#take all of the shapefiles in a directory and compress them into individual zip files
#
#########################################################################################

#import workspace

import arcpy, os
from arcpy import env
from os import path as p
import RemoveAddLayer
import zipfile

arcpy.overwriteOutput = True


def ZipShapes(path, outpath):
    arcpy.env.workspace = path
    shapes = arcpy.ListFeatureClasses()

#iterate through list of shapefiles
    for shape in shapes:
        name = p.splitext(shape)[0]
        print name
        zip_path = p.join(out_path, name + '.zip')
        zip = zipfile.ZipFile(zip_path, 'w', compression=zipfile.ZIP_DEFLATED)
        zip.write(p.join(path,shape), shape)
        for f in arcpy.ListFiles('%s*' %name):
            if not f.endswith('.shp'):
                zip.write(p.join(path,f),f)
        print 'All file written to %s' %zip_path
        zip.close()


if __name__ == '__main__':

    path = r"Database Connections\ims to plainfield.sde\gisedit.DBO.MGU_Will"
    outpath = r"W:\Data"

    ZipShapes(path, outpath)

Here's the same code as I did originally. The only thing I changed is the path variable. But I got this error (below):

0 Kudos
DarrenWiens2
MVP Honored Contributor

out_path and outpath are different.

JaredPilbeam1
Occasional Contributor

They are, thanks for noticing.

After correcting them I ran it and got this error which is new to me:

0 Kudos
RebeccaStrauch__GISP
MVP Esteemed Contributor

I'm curious, why do you have shape files in what appears to be a SDE database? 

path = r"Database Connections\ims to plainfield.sde\gisedit.DBO.MGU_Will"

Maybe the shapes are coming from a different location and I am misreading.  But if they are, can you export them to shape files in a temp folder and zop from there?

0 Kudos