6

I have App dir inside Release dir

$ cd Release
$ tree
.
`-- App
    |-- App.exe
    ..........

and I am trying to create App-1.0.zip in the Release dir containg App with all its content. That is after unpacking App-1.0.zip I would get this App dir.

I tried shutil.make_archive but when I do this

import shutil

shutil.make_archive('App-1.0', 'zip', '.')

from Release dir, I get 48 byte App-1.0.zip inside App-1.0.zip besides the App dir. That is it adds this unfinished archive to itself.

Is there any way to avoid that except creating the archive in temp dir and moving?

I tried to set base_dir and use App as root_dir

shutil.make_archive('App-1.0', 'zip', 'App', 'App')

but I get error that App is not found when I set base_dir.

Traceback (most recent call last):
  File ".......archive.py", line 4, in <module>
    shutil.make_archive('App-1.0', 'zip', 'App', 'App')
  File "C:\Users\Alex\.virtualenvs\....-nAKWzegL\lib\shutil.py", line 800, in make_archive
    filename = func(base_name, base_dir, **kwargs)
  File "C:\Users\Alex\.virtualenvs\....-nAKWzegL\lib\shutil.py", line 686, in _make_zipfile
    zf.write(path, path)
  File "C:\Users\Alex\AppData\Local\Programs\Python\Python36-32\Lib\zipfile.py", line 1594, in write
    zinfo = ZipInfo.from_file(filename, arcname)
  File "C:\Users\Alex\AppData\Local\Programs\Python\Python36-32\Lib\zipfile.py", line 484, in from_file
    st = os.stat(filename)
FileNotFoundError: [WinError 2] The system cannot find the file specified: "'App'"

The same for '/App' and './App'. With full path it works, but I get all parent dirs, not just App.

Python 3.6.4 (v3.6.4:d48eceb, Dec 19 2017, 06:04:45) [MSC v.1900 32 bit (Intel)] on win32

ekhumoro
  • 115,249
  • 20
  • 229
  • 336
Alex P.
  • 3,697
  • 9
  • 45
  • 110
  • [Read the docs](https://docs.python.org/3.6/library/shutil.html#shutil.make_archive): _root_dir is a directory that will be the root directory of the archive; for example, we typically chdir into root_dir before creating the archive._ You told it to create the archive in `Release/App` not `Release`. – tdelaney Mar 24 '18 at 18:18
  • @tdelaney you mean my second attempt? Yes, I know, I was trying to add App/ prefix using base_dir. – Alex P. Mar 24 '18 at 18:33
  • No, in that attempt, you were also setting `root_dir` to `App`. The doc tells you that it changes into `root_dir` and then creates the archive file from there. @ekhumoro 's first example works because it doesn't change `root_dir`. – tdelaney Mar 24 '18 at 19:15
  • @tdelaney Yes, if I set `root_dir` to `App` and leave default `base_dir` (`.`) then it simply puts all files (*.exe etc.) to the root of the archive. But I thought that `base_dir` simply adds prefix (like `App/`) and this path doesn't have to exist. – Alex P. Mar 24 '18 at 19:50
  • yeah, `make_archive` isn't very good. It uses `chdir` to go to the root directory, so it has to exist (and since `chdir` is global to the process, your whole program is no longer thread safe for file operations) and its documentation is quite confusing. – tdelaney Mar 24 '18 at 20:13

2 Answers2

4

Here's a couple of solutions that worked or me:

# curdir: Release
shutil.make_archive('App-1.0', 'zip', '.', 'App')

# curdir: ../Release
shutil.make_archive('Release/App-1.0', 'zip', 'Release', 'App')
ekhumoro
  • 115,249
  • 20
  • 229
  • 336
  • hm, looks like it works indeed. I guess I misunderstood something about that `base_dir`. – Alex P. Mar 24 '18 at 18:11
  • See also my answer here: https://stackoverflow.com/questions/46943014/shutil-make-archive-resulting-in-nested-zip-files/52301644#52301644 –  Sep 14 '18 at 14:11
2

What I learned while fighting with this is this:

shutil.make_archive('App-1.0', 'zip', '.', 'App')

While 'App-1.0' is technically a "filename", it must be represented as a path to the file without the extension ('c:\myfiles\myzipfile'). I have not played with all the variants for path names yet, so some of the shortcuts likely work (such as: 'Release/App-1.0').

סטנלי גרונן
  • 2,917
  • 23
  • 46
  • 68