PyInstaller 2.0 bundle file as --onefile
Question: 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:\path\to\my\file\doc.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:\Python27\lib\os.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!


Answer: 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!

