Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
465 views
in Technique[技术] by (71.8m points)

python - PyInstaller 2.0 bundle file as --onefile

I'm trying to bundle my py script as an .exe using PyInstaller 2.0. I am able to bundle the script, but in my script, I need to open a file that should be bundled in the exe (so it's portable). I'm having trouble doing this..

In my .py, I have

filename = 'C:pathomyfiledoc.docx'
data = open(filename,'rb')

I use PyInstaller 2.0 and this works fine on my computer, but if I transfer the exe to another computer it isn't going to work.. PyInstaller 2.0 is pretty new, so there are very few documents on it, and the publisher's documentation is quite "lacking."

Here is the publisher's info on the matter: (I don't think their documentation is up to date, because in the beginning it says use Configure.py, then in other docs it says Configure.py is no longer needed in 2.0)

In a --onefile distribution, data files are bundled within the executable and then extracted at runtime into the work directory by the C code (which is also able to reconstruct directory trees). The work directory is best found by os.environ['_MEIPASS2']. So, you can access those files through:

os.path.join(os.environ["_MEIPASS2"], relativename))

That doesn't really make sense to me, a beginning programmer..

A different document from the publisher says..

In a --onefile distribution, data files are bundled within the executable and then extracted at runtime into the work directory by the C code (which is also able to reconstruct directory trees). The work directory is best found by sys._MEIPASS. So, you can access those files through:

os.path.join(sys._MEIPASS, relativename))

I've experimented around quite a bit with os.environ["_MEIPASS2"] and python doesn't seem to understand os.environment["_MEIPASS2"]. I get this back:

>>> print os.environ["_MEIPASS2"]

Traceback (most recent call last):
  File "<pyshell#0>", line 1, in <module>
    print os.environ["_MEIPASS2"]
  File "C:Python27libos.py", line 423, in __getitem__
    return self.data[key.upper()]
KeyError: '_MEIPASS2'

I also experimented with sys._MEIPASS.. Yeah, python responds 'module' has no attribute '_MEIPASS'.

At this point, I feel like my head is about to explode.. I appreciate PyInstaller's authors for their work, but their documentation is the worst I've ever seen! I just need someone to help me bundle my file into the exe. I would really like to use PyInstaller 2.0+ since all the .spec stuff confuses me with previous versions of PyInstaller.

BTW, I'm using Win8 64bit with python 2.7.3

PLEASE HELP!

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

OMG! This PyInstaller really confused me for a bit. If my previous post sounds a little "ranty", sorry about that.. Anyways, for anyone trying to include a file in a --onefile PyInstaller package this worked for me:

Include this in your .py script:

filename = 'myfilesname.type'
if hasattr(sys, '_MEIPASS'):
    # PyInstaller >= 1.6
    chdir(sys._MEIPASS)
    filename = join(sys._MEIPASS, filename)
elif '_MEIPASS2' in environ:
    # PyInstaller < 1.6 (tested on 1.5 only)
    chdir(environ['_MEIPASS2'])
    filename = join(environ['_MEIPASS2'], filename)
else:
    chdir(dirname(sys.argv[0]))
    filename = join(dirname(sys.argv[0]), filename)

credit to someone online whose name I don't remember.. (sorry it's late and I'm exhausted!)

Then, if you're using PyInstaller2.0, in cmd, from the pyinstaller-2.0 dir, you can run

pyinstaller.py --onefile myscriptsname.py

That will create a myscriptsname.spec file in the pyinstaller-2.0 dir. It will also create an exe, but that won't work. It will be updated later. Now edit that .spec, and add the following a.datas line (remember datas, not data). I included a little extra in the .spec file just for reference.

a = Analysis(['ServerTimeTest_nograph.py'],
             pathex=['c:\Python27\pyinstaller-2.0'],
             hiddenimports=[],
             hookspath=None)
a.datas += [('myfilesname.type','C:\path\to\my\file\myfilesname.type','DATA')]
pyz = PYZ(a.pure)

Now, back in cmd, run

pyinstaller.py --onefile myscriptsname.spec

This will update your .exe in the /dist dir.

Maybe there's a better way, or a prettier way, but this worked for me!


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...