Working with Robot Framework, I'm trying to zip a directory with one files and three subdirectories containing files. I'm using the ArchiveLibrary and the keyword Create Zip From Files In Directory. The result is a zipped directory containing the one file in the top directory and three empty subfolders.
How can I adjust the library so that also the subfolder's content is included?
This is how the keyword is originally defined:
def create_zip_from_files_in_directory(self, directory, filename):
''' Take all files in a directory and create a zip package from them
`directory` Path to the directory that holds our files
`filename` Path to our destination ZIP package.
'''
if not directory.endswith("/"):
directory = directory + "/"
zip = zipfile.ZipFile(filename, "w")
files = os.listdir(directory)
for name in files:
zip.write(directory + name, arcname=name)
zip.close()
Link to the complete library.
I've been experimenting with os.walk, without success.
How the keyword is used in the .robot file:
Zip xml file
${zipfilename}= set variable komplett.zip
Create zip from Files in directory ../xml/komplett/ ${zipfilename}
If it makes a difference, I really only need to solve this specific case, not a general one, meaning that I don't mind typing in paths to each directory and then join that somehow, I just don't understand how to do it... Also, I use PyCharm as editor, not RIDE.
EDIT: when using the library version 0.4 and up, you can choose whether subdirectories should be included. E.g.:
Create Zip From Files In Directory ../xml/komplett/ no_sub_folders.zip
Create Zip From Files In Directory ../xml/komplett/ dir_and_sub_folders.zip sub_directories=${true}
The keyword for creating tar is a bit different - by default it includes the files in subdirectories, and now you have an option not to:
Create Tar From Files In Directory ../xml/komplett/ dir_and_sub_folders.tar
Create Tar From Files In Directory ../xml/komplett/ no_sub_folders.tar sub_directories=${false}
The default values of sub_directories
are based on the preexisting behavior, not to break exisiting usages in test cases.
Original answer, for versions < 0.4:
If you're willing to patch the library, this code should do:
zip = zipfile.ZipFile(filename, "w")
for path, _, files in os.walk(directory):
for name in files:
file_to_archive = os.path.join(path, name)
# get rid of the starting directory - so the zip structure is top-level starting from it
file_name = path.replace(directory, '')
file_name = os.path.join(file_name, name)
zip.write(file_to_archive, arcname=file_name) # set the desired name in the archive by the arcname argument
zip.close()
Edit: preserves the sub-directory structure for files in - subdirectories. The generated file is with top-level the target directory, and all its subdirectories - beneath it (as opposed to the archive preserving the full path to the target directory)
The arcname
argument controls what is the name of a file stored in the archive - and through line 7, we are preserving the relative directory plus the file name.
Always use os.path.join
cause it automatically takes care of differences in the different file systems (ntfs/linux/etc).
If the final solution works for you, don't forget to propose a patch to the library owner - give back to the community :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With