CX Freeze: erro em Python no programa principal-erro do 'ImportError': a carga do DLL falhou

estou a construir uma pequena ferramenta Python 3.6.5 que pega num documento XML e emite todos os seus XPaths. Funciona bem, no entanto preciso de distribuí-lo de forma EXE. Eu estou correndo em Win10 e só precisa fornecer para Win10 usuários.

O meu código principal é:

from tkinter import filedialog
from tkinter import *
from pathlib import Path
import winsound
from lxml import etree
import csv

root = Tk()

root.geometry("250x200")
root.resizable(0, 0)


class gui:
    def __init__(self, master):
        self.master = master
        master.title("XGen")

        self.welcome = Label(master, text="Welcome to")
        self.welcome.config(font=("Arial", 10))
        self.welcome.pack()

        self.header = Label(master, text="The XPath Generator")
        self.header.config(font=("Arial", 16))
        self.header.pack()

        self.description = Label(master, text="This Tool Takes in an XML Document\nand Provides all its XPaths")
        self.description.config(font=("Arial", 10))
        self.description.pack()

        self.greet_button = Button(master, text="Select Input XML", command=self.greet)
        self.greet_button.pack()

        self.reportFilename = Label(master, text="")
        self.reportFilename.pack()

        self.reportProgress = Label(master, text="")
        self.reportProgress.pack()

        # self.close_button = Button(master, text="Close", command=master.quit)
        # self.close_button.pack()

    def greet(self):
        print("File Selection Started")

        from_file_path = filedialog.askopenfilename(initialdir="/",
                                                    title="Select file",
                                                    filetypes=(("XML Files", "*.xml"), ("all files", "*.*")))

        from_file_path_split = Path(from_file_path).parts
        to_file_path = ''

        if from_file_path is '':
            self.reportFilename.config(text="You Did not Select a File")
            print("No File Selected. File Selection Ended")

        else:
            self.reportFilename.config(text="You Selected " + from_file_path_split[-1])
            print("From File Path = " + from_file_path)
            print("File Name = " + from_file_path_split[-1])
            to_file_path = filedialog.asksaveasfilename(initialdir=from_file_path,
                                                        title="Save As",
                                                        filetypes=(("CSV Files", "*.csv"), ("all files", "*.*")))

        if to_file_path is '' or to_file_path == 'Null':
            self.reportProgress.config(text="Please select a Save Location")
        # elif to_file_split[-1][:4] == "xsd":
        else:
            to_file_split = Path(to_file_path).parts
            to_file_name = to_file_split[-1]
            print("Filename = " + to_file_name)

            to_file_extension = to_file_split[-1][-4:]
            print("Last 4 chars = " + to_file_extension)

            if to_file_extension == ".csv":
                pass
            else:
                to_file_path = to_file_path + ".csv"
                # to_file_name = to_file_path
                print("To File Path = " + to_file_path)

            if from_file_path == '' or to_file_path == '' or to_file_path == 'Null':

                self.reportProgress.config(text="Please Select a Valid XML File")
                winsound.PlaySound("SystemExclamation", winsound.SND_ALIAS)
                print("Bad File, Try Again")

            else:
                out(from_file_path, to_file_path)

                self.reportProgress.config(text="Generated " + Path(to_file_path).parts[-1])
                print("XGen Complete")


def out(in_path, out_path):
    with open(in_path, 'r') as source_file:
        xml = source_file.read()

    root = etree.fromstring(xml)

    tree = etree.ElementTree(root)

    line = ['XPath', 'Attribute Name', 'Current Data']

    if out_path is None:
        return 1
    else:
        pass

    with open(out_path, 'w', newline='') as csv_file:
        csv_writer = csv.writer(csv_file, delimiter=',', quotechar='"', quoting=csv.QUOTE_ALL)
        csv_writer.writerow(line)
        for e in root.iter():
            path = tree.getpath(e)
            list_of_attributes = []
            nodes = root.xpath(path)
            for node in nodes:
                attrs = []
                for att in node.attrib:
                    attrs.append(("@" + att, node.attrib[att]))
                list_of_attributes.append(attrs)
                for attributes in list_of_attributes:
                    line = [path, None]
                    csv_writer.writerow(line)
                    if len(attributes) == 0:
                        pass
                    else:
                        for x in range(len(attributes)):
                            xpath = path + attributes[x][0]
                            current_data = (attributes[x][1])
                            attribute_name = attributes[x][0]
                            line = [xpath, attribute_name, current_data]
                            csv_writer.writerow(line)


my_gui = gui(root)
root.mainloop()
(Por favor, perdoe o código confuso! Eu pretendo limpá-lo para a próxima versão!)

setup.py contém o seguinte;

import sys
from cx_Freeze import setup, Executable

base = None
if sys.platform == 'win32':
    base = 'Win32GUI'

executables = [
    Executable('xin.py', base=base)
]

setup(name='XGen',
      version='0.1',
      description='XGen',
      executables=executables
      )
Isto permite ao programa construir um EXE, No entanto, quando esse EXE é executado, devolve este erro.

cx_Freeze: Python error in main script

Tenho procurado soluções em todo o lado.

    Encontrei uma sugestão de que desinstalar todas as versões do Python, então instalar apenas uma pode funcionar, mas nenhuma alegria. Já experimentei Py2exe, mas isso também não funciona. Encontrei outra sugestão de que o caminho podia estar incorrecto, por isso verifiquei e tudo parece correcto.

como sugerido pelo texto de erro, eu também tentei verificar se o tkinter está devidamente instalado. Não só este programa pode correr através do Python, mas também o IDLE permite-me import tkinter.

O que poderia estar a causar o cx_Freeze para lançar este erro?

Obrigado!

Author: James Geddes, 2018-06-27

1 answers

A localização dos DLLs TK tem de ser adicionada aosetup.py. No Windows 10, isto pode estar na raiz de C: ou em C:\Users\[username]\AppData\Local\Programs\Python\Python36-32/DLLs. Adicione uma variável para guardar esse caminho, tornando-o então um texto bruto com um r principal.

import os
import sys
from cx_Freeze import setup, Executable


PYTHON_INSTALL_DIR = os.path.dirname(os.path.dirname(os.__file__))
os.environ['TCL_LIBRARY'] = os.path.join(PYTHON_INSTALL_DIR, 'tcl', 'tcl8.6')
os.environ['TK_LIBRARY'] = os.path.join(PYTHON_INSTALL_DIR, 'tcl', 'tk8.6')


base = None
if sys.platform == 'win32':
    base = 'Win32GUI'

syspath = r"C:\Users\[username]\AppData\Local\Programs\Python\Python36-32/DLLs"

buildOptions = dict(
    packages=[],
    excludes=[],
    include_files=[syspath + '/tcl86t.dll', syspath + '/tk86t.dll']
)

executables = [
    Executable('xin.py', base=base)
]

setup(name='XGen',
      version='0.1',
      options=dict(build_exe=buildOptions),
      description='XGen',
      executables=executables
      )
Muito obrigado ao Sr. Leeh e ao Deepak M. Birajdar!
 0
Author: James Geddes, 2018-06-28 10:19:11