AlJohri / docx2pdf

MIT License
506 stars 96 forks source link

Exception occurred 'This file is in use by another application or user' #19

Closed Teut2711 closed 4 years ago

Teut2711 commented 4 years ago

Hi I was stuck at this error from 2 days. I 'm running a Python Script from a c# shell. I am using https://pypi.org/project/docopt/ to fill a word form and then convert it to pdf. I 'm using office 365 and win 10 64 bit.

Traceback (most recent call last):
  File "runpy.py", line 192, in _run_module_as_main
  File "runpy.py", line 85, in _run_code
  File "C:\Users\Dell\Desktop\masprojapp\python\python-3.8.0-embed-amd64\Scripts\docx2pdf.exe\__main__.py", line 7, in <module>
  File "c:\users\dell\desktop\masprojapp\python\python-3.8.0-embed-amd64\lib\site-packages\docx2pdf\__init__.py", line 170, in cli
    convert(args.input, args.output, args.keep_active)
  File "c:\users\dell\desktop\masprojapp\python\python-3.8.0-embed-amd64\lib\site-packages\docx2pdf\__init__.py", line 106, in convert
    return windows(paths, keep_active)
  File "c:\users\dell\desktop\masprojapp\python\python-3.8.0-embed-amd64\lib\site-packages\docx2pdf\__init__.py", line 32, in windows
    doc = word.Documents.Open(str(docx_filepath))
  File "<COMObject <unknown>>", line 5, in Open
pywintypes.com_error: (-2147352567, 'Exception occurred.', (0, 'Microsoft Word', 'This file is in use by another application or user.\r (C:\\Users\\Dell\\...\\Temp\\tmpcj1b9swc.docx)', 'wdmain11.chm', 24937, -2146822831), None)
  0%|                                                                                                                 | 0/1 [00:00<?, ?it/s]

Code:

import os
import sys
import pandas as pd
import configparser
from docxtpl import DocxTemplate
import jinja2
from num2words import num2words
import json
from docx2pdf import convert
from sys import platform
import tempfile

BASE_DIR = os.path.abspath(os.path.dirname(__file__))

# --------------load configurations----------------
def get_configurations(config):
    config.optionxform = str
    config.read(os.path.join(BASE_DIR, "vars.cfg"))
    return config
# --------------load configurations----------------

config = get_configurations(configparser.RawConfigParser())
FILES_FOLDER = os.path.join(BASE_DIR, config["FILES"]["FILES_FOLDER"])

def convert_to_pdf(doc):

    from comtypes import client

    word = client.CreateObject('Word.Application')
    new_name = os.path.join(FILES_FOLDER, config["DOWNLOAD"]["DOWNLOAD_FILE_AS"])
    wdFormatPDF = 17
    doc = word.Documents.Open(doc)
    doc.SaveAs(new_name, FileFormat=wdFormatPDF)
    doc.Close()
    word.Quit()

def get_jinja_env():
    def to_words(value):
        value = value.strip()
        if value:
            return num2words(int(value), lang="en_IN").upper()
        return value

    jinja_env = jinja2.Environment()
    jinja_env.filters["to_words"] = to_words
    return jinja_env

def save_docx_object(opt, row):

    row = row.to_dict()

    file_path = r'C:\Users\Dell\Desktop\masprojapp\python\DEMATTENDER FORM for LOF.docx'#

    doc = DocxTemplate(file_path)

    context = {
        # value is tag name which is placed in word file and key is always column name of db
        value: row[key]
        for key, value in config._sections["TAGS"].items()
    }

    jinja_env = get_jinja_env()

    doc.render(context, jinja_env)
    temp = tempfile.NamedTemporaryFile(suffix=".docx")
    doc.save(temp)
    return temp

def search_row_in_database(opt, value):
    df = pd.read_csv(
        os.path.join(FILES_FOLDER, config["FILES"]["EXCEL_FILE_NAME"]),
        dtype=str,
        keep_default_na=False,
    )
    return df[df[opt] == value]

def get_pdf(opt, row):
    temp = save_docx_object(opt, row)
    import subprocess

    if platform == "linux" or platform == "linux2":
        subprocess.run(
            [
                "abiword",
                "--to=pdf",
                os.path.join(FILES_FOLDER, config["DOWNLOAD"]["DOWNLOAD_FILE_AS"]),
            ]
        )
    elif platform == "win32":
        subprocess.run(
            [
                os.path.join(BASE_DIR, "python-3.8.0-embed-amd64", "Scripts", "docx2pdf"),
                os.path.join(FILES_FOLDER, temp.name),
                os.path.join(FILES_FOLDER, config["DOWNLOAD"]["DOWNLOAD_FILE_AS"]),
            ],
            shell=True )

def main(opt, value):

    row = search_row_in_database(opt, value)

    # check if a single row with that ID exists
    if len(row) == 1:
        row = row.squeeze()
        get_pdf(opt, row)
        print(
            json.dumps(
                {
                    "status": "Success",
                    "path": os.path.join(
                        FILES_FOLDER, config["DOWNLOAD"]["DOWNLOAD_FILE_AS"]
                    ),
                }
            )
        )
    # no rows with that ID found
    elif len(row) == 0:
        print(json.dumps({"status": "ErrorDNE"}))
    # in case of multiple rows with that ID exists
    else:
        print(json.dumps({"status": "ErrorMRE"}))

if __name__ == "__main__":
    main(sys.argv[1], sys.argv[2])
Teut2711 commented 4 years ago

The issue was that temp which is the named temporary file was opened. I first of all added delete=False to the arguments, secondly I added temp.close() just before subprocesses.run .