Last active
April 28, 2019 17:32
-
-
Save niazangels/2cc87f6cc2d4e3379bccfa777e1bd529 to your computer and use it in GitHub Desktop.
Save a pdf safely in python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# https://github.com/mstamy2/PyPDF2/issues/53 | |
import os, shutil, tempfile | |
from pathlib import Path | |
# Things from the subprocess module don't rely on the shell unless you | |
# explicitly ask for it and can accept a pre-split list of arguments, | |
# making calling subprocesses much safer. | |
# (If you really do need to split quoted stuff, use shlex.split() instead) | |
from subprocess import check_call | |
# [...] | |
# Use try/finally to ensure our cleanup code gets run | |
try: | |
# There are a lot of ways to mess up creating temporary files in a way | |
# that's free of race conditions, so just use mkdtemp() to safely | |
# create a temporary folder that only we have permission to work inside | |
# (We ask for it to be made in the same folder as filename because /tmp | |
# might be on a different drive, which would make the final overwrite | |
# into a slow "copy and delete" rather than a fast os.rename()) | |
tempdir = tempfile.mkdtemp(dir=SOURCE_FILE.parent) | |
# I'm not sure if a qpdf failure could leave the file in a halfway | |
# state, so have it write to a temporary file instead of reading from one | |
temp_out= SOURCE_FILE.parent / f'qpdf_{SOURCE_FILE.name}' | |
# Avoid the shell when possible and integrate with Python errors | |
# (check_call() raises subprocess.CalledProcessError on nonzero exit | |
check_call(['qpdf', "--password=", '--decrypt', SOURCE_FILE, temp_out]) | |
# I'm not sure if a qpdf failure could leave the file in a halfway | |
# state, so write to a temporary file and then use os.rename to | |
# overwrite the original atomically. | |
# (We use shutil.move instead of os.rename so it'll fall back to a copy | |
# operation if the dir= argument to mkdtemp() gets removed) | |
shutil.move(temp_out, SOURCE_FILE) | |
print('File Decrypted (qpdf)') | |
finally: | |
# Delete all temporary files | |
shutil.rmtree(tempdir) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment