Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PyInstaller 2.0 bundle file as --onefile

Tags:

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!

like image 642
user1914730 Avatar asked Dec 19 '12 06:12

user1914730


People also ask

What is Onefile in PyInstaller?

When we specify the onefile option, to the PyInstaller, it unpacks all the files to a TEMP directory, executes the file, and later discard the TEMP folder. When you specify the add-data option along with onefile, then you need to read the data referred to in the TEMP folder.

Does PyInstaller work with libraries?

pip will install PyInstaller's dependencies along with a new command: pyinstaller . PyInstaller can be imported in your Python code and used as a library, but you'll likely only use it as a CLI tool. You'll use the library interface if you create your own hook files.

Does PyInstaller include all dependencies?

PyInstaller bundles a Python application and all its dependencies into a single package. The user can run the packaged app without installing a Python interpreter or any modules. PyInstaller reads a Python script written by you.

How do I bundle a pyinstaller project into one file?

To bundle your project into a single file, you can build with a command like this: $ pyinstaller cli.py --onefile With the above command, your dist/ folder will only contain a single executable instead of a folder with all the dependencies in separate files.

Does pyinstaller--OneFile work on Windows?

There are some applications all packed by pyinstaller2.0 with --onefile option on windows. One of them call others through subporcess, but the others can't startup. The other applications work when startup through cmd or other applications not packed by pyinstaller2.0. pyinstaller 1.5 works.

What is pyinstaller in Python?

PyInstaller bundles a Python application and all its dependencies into a single package. The user can run the packaged app without installing a Python interpreter or any modules. PyInstaller supports Python 3.7 and newer, and correctly bundles many major Python packages such as numpy, matplotlib, PyQt, wxPython, and others.

How to add image files in pyinstaller?

You have to add your image files in "datas" (either in your spec files or with a PyInstaller hook script) using the single line base_path = getattr (sys, '_MEIPASS', '.')+'/' to get a "root_path" variable to concatenation to all your files' paths. Add "datas = ['Location of your file']," before "hiddenimports = []". It will do.


1 Answers

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!

like image 79
user1914730 Avatar answered Sep 21 '22 01:09

user1914730