docx2pdf
docx2pdf copied to clipboard
Converting a docx I edited with Python3.8 to pdf gives me an error
First of all, I think this module is awesome as there are nearly no other easy options to convert a docx to a pdf using Python. So if this problem could be solved, I'd be very happy.
I created a script that opens a docx, edit some text variables according to a Tkinter Entry input and then saves it as a new docx. I then want to convert it to a pdf so that I don't need to do that manually but that's the part which I can't get to succeed. I'll share with you my code and all the output it gives me:
My code:
from docx import Document
from docx.shared import Pt
from tkinter import *
from tkinter import messagebox
from tkinter import font as tkfont
from docx2pdf import convert
import docx2pdf
import os
print(docx2pdf.__version__)
root = Tk()
root.config(background='#009688')
root.wm_withdraw()
root.update()
root.title('Contractmaker')
naamhuurder = StringVar(root)
geboortedatum = StringVar(root)
adreshuurder = StringVar(root)
pchuurder = StringVar(root)
woonplaatshuurder = StringVar(root)
adresapp = StringVar(root)
typekamer = StringVar(root)
einddatumcontract = StringVar(root)
begindatumcontract = StringVar(root)
beginmaand1 = StringVar(root)
eindmaand1 = StringVar(root)
# Make all entries empty
def clear():
entryNames = [naamhuurderr, geboortedatumm, adreshuurderr, pchuurderr, woonplaatshuurderr,
einddatumcontractt, begindatumcontractt,
beginmaand11, eindmaand11]
for i in entryNames:
i.delete(0, END)
# The function that changes the variables and saves it as a pdf in the correct folder
def contractupdater():
global huur
global appwp
global pcapp
# open the document and set the fontsize and style
doc = Document('./Contract.docx')
styles = doc.styles['Normal']
font = styles.font
font.size = Pt(9)
font.name = 'Arial'
# Remove the spaces from the adress line
oldadres = adresapp.get()
nospaceadres = oldadres.replace(' ', '').lower()
# Handle the dropdown menus
if adresapp.get() == 'Slotlaan 73' or adresapp.get() == 'Slotlaan 77':
pcapp = '2902AK'
appwp = 'Capelle aan den IJssel'
elif adresapp.get() == 'Albert Cuypstraat 22':
pcapp = '2902GC'
appwp = 'Capelle aan den IJssel'
if typekamer.get() == 'Grote kamer':
huur = '510'
elif typekamer.get() == 'Kleine kamer':
huur = '435'
elif typekamer.get() == 'Grote kamer gedeeld':
huur = '800'
# Check whether the date has been filled in correctly
try:
einddatum = einddatumcontract.get()
laatstecijferpluseen = str(int(einddatum[-1]) + 1)
verlengentot = str(einddatum[:-1])
verlengentot += laatstecijferpluseen
except:
verlengentot = 'error'
# Replace the variables with the input
Dictionary = {"naam.vv": naamhuurder.get(), "gb.vv": geboortedatum.get(), 'adres.vv': adreshuurder.get(),
'postcode.vv': pchuurder.get(),
'woonplaats.vv': woonplaatshuurder.get(), 'appdres.vv': adresapp.get(), 'apppc.vv': pcapp,
'appwp.vv': appwp, 'typekamer.vv': typekamer.get(), 'enddate.vv': einddatumcontract.get(),
'begindate.vv': begindatumcontract.get(), 'verlengdatum.vv': verlengentot, 'huur.vv': huur,
'begineerstemaand.vv': beginmaand1.get(), 'eindeerstemaand.vv': eindmaand1.get()}
# Check whether all Entry received input
entriesWithInput = []
for key, value in Dictionary.items():
if len(value) > 0:
entriesWithInput.append(value)
# Replace the variables of in the docx to the input if it fullfills the if statements
if len(entriesWithInput) == len(Dictionary):
if verlengentot != 'error':
for i in Dictionary:
for p in doc.paragraphs:
if p.text.find(i) >= 0:
p.text = p.text.replace(i, Dictionary[i])
# Save changed document at the correct place
doc.save('/Users/Jem/Documents/Huurovereenkomsten/Specifiek/{}/contract{}.docx'.format(nospaceadres,
naamhuurder.get()))
path = '/Users/Jem/Documents/Huurovereenkomsten/Specifiek/{}/contract{}.docx'.format(nospaceadres, naamhuurder.get())
os.chmod(path, 0o777)
convert('/Users/Jem/Documents/Huurovereenkomsten/Specifiek/{}/contract{}.docx'.format(nospaceadres,
naamhuurder.get()))
# Show user that the file has succesfully been made
messagebox.showinfo('Succesvol opgeslagen', 'Het contract is gemaakt en opgeslagen in de folder.')
else:
messagebox.showerror('Vul alleen cijfers in bij de datum', 'Vul een datum als volgt in: dd-mm-jjjj')
else:
messagebox.showerror('Er ging iets mis',
'Controleer of alle data correct is ingevuld en probeer opnieuw.')
# GUI stuff that takes care of the scrollbar
def on_configure(event):
canvas.configure(scrollregion=canvas.bbox('all'))
def on_mousewheel(event):
canvas.yview_scroll(int(event.delta), 'units')
# Create some fonts
bold_font = tkfont.Font(weight='bold')
# Create the actual GUI
canvas = Canvas(root, width=450, height=550)
canvas.config(background='#009688')
canvas.pack(side=RIGHT)
scrollbar = Scrollbar(root, command=canvas.yview)
# scrollbar.pack(side=RIGHT, fill='y')
canvas.configure(yscrollcommand=scrollbar.set)
canvas.bind('<Configure>', on_configure)
canvas.bind_all('<MouseWheel>', on_mousewheel)
frame = Frame(canvas)
frame.config(background='#009688')
canvas.create_window((0,0), window=frame)
labelNaamhuurder = Label(frame, text='Naam huurder', bg='#009688', font=bold_font).grid(row=0, column=0, sticky=W, padx=(30, 0), pady=(15, 0))
naamhuurderr = Entry(frame, textvariable=naamhuurder, relief=FLAT, highlightcolor='#9DCCFD')
naamhuurderr.focus_set()
naamhuurderr.grid(row=0, column=2, pady=(15, 0))
labelGeboortedatum = Label(frame, text='Geboortedatum', bg='#009688', font=bold_font).grid(row=1, column=0, pady=(15, 0), sticky=W, padx=(30, 0))
geboortedatumm = Entry(frame, textvariable=geboortedatum, relief=FLAT, highlightcolor='#9DCCFD')
geboortedatumm.grid(row=1, column=2, pady=(15, 0))
labelAdreshuurder = Label(frame, text='Adres huurder', bg='#009688', font=bold_font).grid(row=2, column=0, pady=(15, 0), sticky=W, padx=(30, 0))
adreshuurderr = Entry(frame, textvariable=adreshuurder, relief=FLAT, highlightcolor='#9DCCFD')
adreshuurderr.grid(row=2, column=2, pady=(15, 0))
labelPchuurder = Label(frame, text='Postcode huurder', bg='#009688', font=bold_font).grid(row=3, column=0, pady=(15, 0), sticky=W, padx=(30, 0))
pchuurderr= Entry(frame, textvariable=pchuurder, relief=FLAT, highlightcolor='#9DCCFD')
pchuurderr.grid(row=3, column=2, pady=(15, 0))
labelWoonplaatshuurder = Label(frame, text='Woonplaats huurder', bg='#009688', font=bold_font).grid(row=4, column=0, pady=(15, 0), sticky=W, padx=(30, 0))
woonplaatshuurderr = Entry(frame, textvariable=woonplaatshuurder, relief=FLAT, highlightcolor='#9DCCFD')
woonplaatshuurderr.grid(row=4, column=2, pady=(15, 0))
labelAdresapp = Label(frame, text='Adres appartement', bg='#009688', font=bold_font).grid(row=5, column=0, pady=(15, 0), sticky=W, padx=(30, 0))
appartementen = {'Slotlaan 73', 'Slotlaan 77', 'Albert Cuypstraat 22'}
adresapp.set('Slotlaan 73') # Default option
dropdownMenuhuur = OptionMenu(frame, adresapp, *appartementen)
dropdownMenuhuur.config(width=18)
dropdownMenuhuur.grid(row=5, column=2, pady=(15, 0))
labelTypekamer = Label(frame, text='Type kamer', bg='#009688', font=bold_font).grid(row=6, column=0, pady=(15, 0), sticky=W, padx=(30, 0))
typeKamers = {'Grote kamer', 'Kleine kamer', 'Grote kamer gedeeld'}
typekamer.set('Grote kamer') # Default option
dropdownMenutypekamer = OptionMenu(frame, typekamer, *typeKamers)
dropdownMenutypekamer.config(width=18)
dropdownMenutypekamer.grid(row=6, column=2, pady=(15, 0))
labelEinddatumcontract = Label(frame, text='Eind datum contract', bg='#009688', font=bold_font).grid(row=7, column=0, pady=(15, 0), sticky=W, padx=(30, 0))
einddatumcontractt = Entry(frame, textvariable=einddatumcontract, relief=FLAT, highlightcolor='#9DCCFD')
einddatumcontractt.grid(row=7, column=2, pady=(15, 0))
labelBegindatumcontract = Label(frame, text='Begin datum contract', bg='#009688', font=bold_font).grid(row=8, column=0, pady=(15, 0), sticky=W, padx=(30, 0))
begindatumcontractt = Entry(frame, textvariable=begindatumcontract, relief=FLAT, highlightcolor='#9DCCFD')
begindatumcontractt.grid(row=8, column=2, pady=(15, 0))
labelBeginmaand1 = Label(frame, text='Begin van de eerste maand', bg='#009688', font=bold_font).grid(row=9, column=0, pady=(15, 0), sticky=W, padx=(30, 0))
beginmaand11 = Entry(frame, textvariable=beginmaand1, relief=FLAT, highlightcolor='#9DCCFD')
beginmaand11.grid(row=9, column=2, pady=(15, 0))
labelEindmaand1 = Label(frame, text='Eind van de eerste maand', bg='#009688', font=bold_font).grid(row=10, column=0, pady=(15, 0), sticky=W, padx=(30, 0))
eindmaand11 = Entry(frame, textvariable=eindmaand1, relief=FLAT, highlightcolor='#9DCCFD')
eindmaand11.grid(row=10, column=2, pady=(15, 0))
empty = Button(frame, text='Opnieuw', command=clear, font=bold_font)
empty.config(width=10, fg='#009688', borderwidth=0, relief=RAISED)
empty.configure(highlightbackground='#009688')
empty.grid(row=11, column=0, pady=(25, 0), padx=(80, 0))
converter = Button(frame, text='OK', command=contractupdater, font=bold_font)
converter.config(width=10, fg='#009688', borderwidth=2, relief=RAISED)
converter.configure(highlightbackground='#009688')
converter.grid(row=11, column=2, pady=(25, 0), padx=(0, 80))
root.after(1, root.deiconify)
root.mainloop()
Before I added the os.chmod(path, 0o777), it would ask me for permission. After I added that, it wouldn't ask me for permission anymore but it still didn't work. In this SO question, I've also asked my question. After running the above code, it gives me
0%| | 0/1 [00:02<?, ?it/s]
It then opens the file in MS Word but doesn't do anything in Word and then it gives me:
{'input': '/Users/Jem/Documents/Huurovereenkomsten/Specifiek/slotlaan73/contractabc.docx', 'output': '/Users/Jem/Documents/Huurovereenkomsten/Specifiek/slotlaan73/contractabc.pdf', 'result': 'error', 'error': 'Error: Er heeft zich een fout voorgedaan.'}
'Er heeft zich een fout voorgedaan.' is Dutch for: an error has occurred.
I'm using python 3.8 and docx2pdf 0.1.7
Really hoping you can find a solution for this because, as said, I think this module can be very useful.
hi @Jem2104, if this is something you're still struggling with, can you verify that docx2pdf is the issue by trying to convert this single file using the docx2pdf command line interface?
So you mean by just saving the new updated docx on my laptop and then converting it to pdf through the command line in my IDE?
Yup!
I just tried it and it gave me the exact same problem / error as I explained in my initial post. If I need to check anything else, let me know and I'll try it! :)
Really hoping this is something that can be fixed as this module would make my project perfect
@Jem2104 yes, if possible can you attach a version of your document that reproduces the error? of course stripped of any sensitive or personal information
Do you mean the code I'm working with? If so, please have a look at the original post of this thread. If you need it in any other format, please let me know and I'll provide it.
If you mean the original docx that get's updated into a new docx and then saved as a new docx before being converted to pdf: this is the one Contract.GithubVersion.docx
Unfortunately I'm not experienced enough with JXA to find out what's going wrong, but I had the same problem. I solved it by making this AppleScript version -- save it as an applescript droplet app and then just drag the files/folders to convert onto it. You may need to 'prime' word's permissions so that it can access the folders by first dragging the parent folder onto Word, otherwise you could get a 'grant permission' dialog for each file.
@sourtin I'm getting "grant folder access" errors too, what do you mean by "dragging the parent folder onto Word" to 'prime' the permissions? That seems like what I want to do but not sure exactly how...
@sourtin I'm getting "grant folder access" errors too, what do you mean by "dragging the parent folder onto Word" to 'prime' the permissions? That seems like what I want to do but not sure exactly how...
It's been a while, but I think what I did was:
- Let's say you've got "World.docx" in a folder "Hello".
- Make sure Microsoft Word is launched.
- Drag the folder "Hello" onto the Microsoft Word icon in the dock. Nothing much should happen, but the permissions should now be 'primed'.
- You should now be able to use the AppleScript Droplet: drag files and or folders onto the Droplet App (make sure all the files/folders are inside a primed folder, such as "Hello" from earlier).
@wearley thanks, I was actually trying to get docx2pdf
to work, but that didn't work for me. However what DID work was using this applescript I could run with automator as a quick action:
use scripting additions
property word_docs : {"org.openxmlformats.wordprocessingml.document", "com.microsoft.word.doc"}
property default_path : (path to desktop) as alias
property Delim : {".docx", ".doc"}
property PDF : ".pdf"
on run {input, parameters}
set outPDF to {}
-- replace Word document extensions with PDF, and append to outPDF list
set {TID, AppleScript's text item delimiters} to {AppleScript's text item delimiters, Delim}
repeat with afile in input
copy item 1 of text items of (afile as text) & PDF to the end of outPDF
end repeat
set AppleScript's text item delimiters to TID
tell application id "com.microsoft.Word"
set visible to false
activate
repeat with i from 1 to count of input
open (item i of input)
set theOutputPath to (item 1 of outPDF)
open for access file theOutputPath
tell active document
save as it file name theOutputPath file format format PDF
close saving yes
end tell
end repeat
quit
end tell
return input
end run
which ALSO didn't work until I specifically added the line open for access file theOutputPath
.
Link here: https://apple.stackexchange.com/questions/269539/applescript-pages-export-to-pdf-fails-due-to-sandbox-permissions
I'm not super sure how all the mac sandbox permissions work, but that fixed it, and the script works without getting the "grant access for this file..." dialog in word.
@AlJohri Is there any way to add anything similar to docx2pdf
to make it work without the permissions dialog?