EnsureDispatch error when using cx_freeze for making exe - python-3.x

I am working with Python 3.4 on Windows 7. My setup file is as follows:
from cx_Freeze import setup, Executable, sys
exe=Executable(
script="XYZ.py",
base="Win32Gui",
)
includefiles=[]
includes=[]
excludes=[]
packages=[]
setup(
version = "1.0",
description = "XYZ",
author = "MAX",
name = "AT",
options = {'build_exe': {'excludes':excludes,'packages':packages,'include_files':includefiles}},
executables = [exe]
)
from distutils.core import setup
import py2exe, sys, os, difflib
sys.argv.append('py2exe')
setup(
options = {'py2exe': {'bundle_files': 1}},
console = [{'script': "XYZ.py"}],
zipfile = None,
)
When the obtained exe is run, an error pops up saying:
...
File "C:\Python34\Lib\site-packages\win32com\client\CLSIDToClass.py", line 46, in GetClass
return mapCLSIDToClass[clsid]
KeyError: '{00020970-0000-0000-C000-000000000046}'
I just can't figure out the problem here. Help, please.
Thanks.

I've just figured out that the problem with EnsureDispatch is within gencache module, it assumes to be in read-only mode when an executable is built with cx_freeze.
The following lines allow cache to be built inside AppData\Local\Temp\gen_py\#.#\ directory in Windows 7 x64:
from win32com.client import gencache
if gencache.is_readonly:
gencache.is_readonly = False
gencache.Rebuild() #create gen_py folder if needed
References:
py2exe/pyinstaller and DispatchWithEvents answer
py2exe.org: UsingEnsureDispatch
P. S. Performance is much better with static dispatch

You are using static proxy which is generated on your disk and which has the compiled executable trouble finding. If you do not know what the static proxy is, you are probably using win32com.client.gencache.EnsureDispatch which generates static proxy automatically.
The easiest way to fix the problem is to use dynamic proxy by using win32com.client.dynamic.Dispatch. Static proxy has some benefits, but there is a high possibility that you do not need it.
You can find more information about static and dynamic proxies to COM objects here: http://timgolden.me.uk/python/win32_how_do_i/generate-a-static-com-proxy.html

Related

DLL problem after compile with cx_freeze when I use win32wnet importation

I create a script that connect to network folder with specific username and password that I don't give to user. This script connecto to network folder for 1 or 2 secondes, do stuff and disconnect after that to be sure user can't access network folder after that.
I work fine in my developpement environment.
I user cx_Freeze to convert my .py to .exe ( I use it for other little program many times )
Problem is that the .exe file works fine only on the same PC where I develop my app. On all other PC it give me error : File " network.py" line 1, in ImportError: DLL load failed: Le module spécifié est introuvable ( in english, it can't find the specified module )
I try to add DLL of win32wnet. but not working.
What I do wrong.
See my code and my import code
'''
import win32wnet
import os
import re
# configure initial parameter
shareFolder = "\\\\ultra\\circuit-bgo"
usager = "foo"
motPasse = "foo"
# use win32wnet to create resorce to connect or disconnect
net_resource = win32wnet.NETRESOURCE()
net_resource.lpRemoteName = shareFolder
# try to disconnect to be sure no connection steel exist
try:
win32wnet.WNetCancelConnection2(net_resource.lpRemoteName,0,0)
except:
pass
# create connection to network folder
laConnection = win32wnet.WNetAddConnection2(net_resource, motPasse, usager, 0)
if os.path.exists(net_resource.lpRemoteName):
print("connection réussi")
# do some stuff, like read write and modify some files ( 1 or 2 secondes )
else:
print("connection ÉCHOUÉ")
# opps, connection failed
# disconnect to the network folder. I don't want user can access the folder by itself
try:
win32wnet.WNetCancelConnection2(net_resource.lpRemoteName,0,0)
except:
pass
'''
Import code with cx_freeze
'''
import os
import sys
from cx_Freeze import setup, Executable
base = None
if sys.platform == 'win32':
base = 'Win32GUI'
#syspath = "c:\\Python32\\Lib\\site-packages\\win32\\perfmondata.dll"
buildOptions = dict(
packages=['win32wnet'],
excludes=[],
include_files=['perfmondata.dll',]
)
executables = [Executable('network.py', base=base)]
setup(name='TestNetwork',
version='0.1',
options=dict(build_exe=buildOptions),
description='NetWork',
executables=executables
)
'''
and I try the basic code when I normaly compile with cx_freeze
this is a batch file:
cxfreeze.bat "c:/Python32/Scripts/network.py" --base-name=Win32GUI --target-dir C:/Python32/Scripts/Dist_Network --icon c:/Python32/Scripts/Logo.ico
After many, many, many test and reinstallation of python and module I need to find DLL that give me problem. I found that 3 DLL files have to be copy to the same folder of my new .exe file ( program ). The 3 DLL files are : pythoncom32.dll, pythoncomloader32.dll and pywintypes32.dll You can find this files on c:\Windows\syswow64 or system32 depend of your python installation (32 bit or 64 bit)
If you have bether solution, you can add it.
Thanks

Python 3.6 Importing a class from a parallel folder

I have a file structure as shown below,
MainFolder
__init__.py
FirstFolder
__init__.py
firstFile.py
SecondFolder
__init__.py
secondFile.py
Inside firstFile.py, I have a class named Math and I want to import this class in secondFile.py.
Code for firstFile.py
class Math(object):
def __init__(self, first_value, second_value):
self.first_value = first_value
self.second_value = second_value
def addition(self):
self.total_add_value = self.first_value + self.second_value
print(self.total_add_value)
def subtraction(self):
self.total_sub_value = self.first_value - self.second_value
print(self.total_sub_value)
Code for secondFile.py
from FirstFolder.firstFile import Math
Math(10, 2).addition()
Math(10, 2).subtraction()
When I tried running secondFile.py I get this error: ModuleNotFoundError: No module named 'First'
I am using Windows and the MainFolder is located in my C drive, under C:\Users\Name\Documents\Python\MainFolder
Possible solutions that I have tried are, creating the empty __init__.py for all main and sub folders, adding the dir of MainFolder into path under System Properties environment variable and using import sys & sys.path.append('\Users\Name\Documents\Python\MainFolder').
Unfortunately, all these solutions that I have found are not working. If anyone can highlight my mistakes to me or suggest other solutions, that would be great. Any help will be greatly appreciated!
There are potentially two issues. The first is with your import statement. The import statement should be
from FirstFolder.firstFile import Math
The second is likely that your PYTHONPATH environment variable doesn't include your MainFolder.
On linux and unix based systems you can do this temporarily on the commandline with
export PYTHONPATH=$PYTHONPATH:/path/to/MainFolder
On windows
set PYTHONPATH="%path%;C:\path\to\MainFolder"
If you want to set it permanently, use setx instead of set

Loading python modules in Python 3

How do I load a python module, that is not built in. I'm trying to create a plugin system for a small project im working on. How do I load those "plugins" into python? And, instaed of calling "import module", use a string to reference the module.
Have a look at importlib
Option 1: Import an arbitrary file in an arbiatrary path
Assume there's a module at /path/to/my/custom/module.py containing the following contents:
# /path/to/my/custom/module.py
test_var = 'hello'
def test_func():
print(test_var)
We can import this module using the following code:
import importlib.machinery
myfile = '/path/to/my/custom/module.py'
sfl = importlib.machinery.SourceFileLoader('mymod', myfile)
mymod = sfl.load_module()
The module is imported and assigned to the variable mymod. We can then access the module's contents as:
mymod.test_var
# prints 'hello' to the console
mymod.test_func()
# also prints 'hello' to the console
Option 2: Import a module from a package
Use importlib.import_module
For example, if you want to import settings from a settings.py file in your application root folder, you could use
_settings = importlib.import_module('settings')
The popular task queue package Celery uses this a lot, rather than giving you code examples here, please check out their git repository

How do I get the OS and system modules into py2exe

I am trying to create a stand alone application for a windows computer I am trying to use the following modules:
os
system
threading
time
But it is not allowing me to import any of these modules it doesn't give me an error code or anything it just will not load the modules into the file! from distutils.core import setup
import py2exe
setup(console=['Evil_unlocker_final.py']
options={
"os":{
"unbuffered": True,
"optimize": 2
}
"sys":{
"unbuffered": True,
"optimize": 2
}
}
)
You do not have to add the os library nor do you have to add the system library the error is in the setup.py file it is not formatted correctly all you need in your setup.py file
setup(console=['Evil_unlocker_final.py'])
That's it the only time that you would need to add in the options function is when you are importing a module that is not built into python for example if you wanted to add in the flask and jinja2 libraries your file would have to also have to add options and your file would look somewhat like this
setup(console=['Evil_unlocker_final.py']
options={
"pip":{
"unbuffered": True,
"optimize": 2
}
"jinja2":{
"unbuffered": True,
"optimize": 2
}
}
)

Py2exe: Embed static files in exe file itself and access them

I found a solution to add files in library.zip via: Extend py2exe to copy files to the zipfile where pkg_resources can load them.
I can access to my file when library.zip is not include the exe.
I add a file : text.txt in directory: foo/media in library.zip.
And I use this code:
import pkg_resources
import zipfile
from cStringIO import StringIO
my_data = pkg_resources.resource_string(__name__,"library.zip")
filezip = StringIO(my_data)
zip = zipfile.ZipFile(filezip)
data = zip.read("foo/media/text.txt")
I try to use pkg_resources but I think that I don't understand something because I could open directly "library.zip".
My question is how can I do this when library.zip is embed in exe?
Best Regards
Jean-Michel
I cobbled together a reasonably neat solution to this, but it doesn't use pkg_resources.
I need to distribute productivity tools as standalone EXEs, that is, all bundled into the one .exe file. I also need to send out notifications when these tools are used, which I do via the Logging API, using file-based configuration. I emded the logging.cfg fileto make it harder to effectively switch-off these notifications i.e. by deleting the loose file... which would probably break the app anyway.
So the following is the interesting bits from my setup.py:
LOGGING_CFG = open('main/resources/logging.cfg').read()
setup(
name='productivity-tool',
...
# py2exe extras
console=[{'script': productivity_tool.__file__.replace('.pyc', '.py'),
'other_resources': [(u'LOGGINGCFG', 1, LOGGING_CFG)]}],
zipfile=None,
options={'py2exe': {'bundle_files': 1, 'dll_excludes': ['w9xpopen.exe']}},
)
Then in the startup code for productivity_tool.py:
from win32api import LoadResource
from StringIO import StringIO
from logging.config import fileConfig
...
if __name__ == '__main__':
if is_exe():
logging_cfg = StringIO(LoadResource(0, u'LOGGINGCFG', 1))
else:
logging_cfg = 'main/resources/logging.cfg'
fileConfig(logging_cfg)
...
Works a treat!!!
Thank you but I found the solution
my_data = pkg_resources.resource_stream("__main__",sys.executable) # get lib.zip file
zip = zipfile.ZipFile(my_data)
data = zip.read("foo/media/doc.pdf") # get my data on lib.zip
file = open(output_name, 'wb')
file.write(data) # write it on a file
file.close()
Best Regards
You shouldn't be using pkg_resources to retrieve the library.zip file. You should use it to retrieve the added resource.
Suppose you have the following project structure:
setup.py
foo/
__init__.py
bar.py
media/
image.jpg
You would use resource_string (or, preferably, resource_stream) to access image.jpg:
img = pkg_resources.resource_string(__name__, 'media/image.jpg')
That should "just work". At least it did when I bundled my media files in the EXE. (Sorry, I've since left the company where I was using py2exe, so don't have a working example to draw on.)
You could also try using pkg_resources.resource_filename(), but I don't think that works under py2exe.

Resources