py2exe and Panda 1.2.3

I am currently trying to get py2exe to compile my panda program into an executable. I am hitting one hitch though. After much tweaking directory paths etc. I got py2exe to succesfully locate the direct package from panda so that it no longer displays the original warning message concerning the direct package panda modules:


 the following modules may be missing
['direct','actor', etc...]

The above warning has been resolved however. Now it compiles correctly giving me this warning error which i believe might be negligible:


 the following modules may be missing
['win32com.gen_py']

and upon runtime it executes but crashes with the following runtime error:


Traceback (most recent call last):
  File "main.py", line 10, in ?
  File "pandac\PandaModules.pyc", line 5, in ?
  File "pandac\libdirectModules.pyc", line 8, in ?
  File "direct\__init__.pyc", line 7, in ?
NameError: name 'exit' is not defined

Has anyone got py2exe to work with panda before (I want it to work with panda 1.2.3) and if not, can anybody point me in the direction of how to fix this problem?
[/code]

Just to update this post, I managed to get py2exe to pack panda up into an executable…

Post Officially Closed

Just to update this post, I managed to get py2exe to pack panda up into an executable…

Post Officially Closed

Excellent!!! Could you explain how you did it? packpanda is great but creates a rather large installation. Could imagine py2exe being faster. Any insights as to how to do it much appreciated!

I second Martin’s request, please tell us how you got it to work.

Thanks

I third the request.
Please tell us how.

see the example below.

also you need to adapt your Panda3D 1.3.0 installation slightly. see discourse.panda3d.org/viewtopic.php?t=2091 for more information regarding the suggested small change.

import os
import glob

from distutils.core import setup
import py2exe

PANDA_DIR = 'C:\\Panda3D-1.3.0'

setup(
    console=['yourMainScript.py'],
    #or make sure you don't open a console window
    #windows=['yourMainScript.py'],
    options = {
        'py2exe' : {
            'unbuffered' : True,
            'optimize' : 2,
            'includes' : [
                # include a list of modules that are not found 
                # by py2exe here
                'mymodule.mysubmodule',
                ],
            'ignores' : [
                # include a list of modules to ignore
                'mydebugmodule.mydebugsubmodule',
                ],
            'dist_dir' : 'dist',
            },
    },
    packages = [
        'direct', 
        'direct.directbase', 
        'direct.showbase',
        'direct.interval', 
        'direct.actor', 
        'direct.gui', 
        'direct.task', 
        'direct.controls',
        'direct.directnotify',
        'direct.directtools',
        'direct.directutil',
        'direct.fsm',
        'direct.cluster',
        'direct.particles',
        'direct.tkpanels',
        'direct.tkwidgets',
        'direct.directdevices',
        'direct.distributed',
        'pandac',
        ],
    package_dir = {
        'direct' : os.path.join(PANDA_DIR, 'direct'),
        'direct.directbase' : os.path.join(PANDA_DIR, 'direct/directbase'), 
        'direct.showbase' : os.path.join(PANDA_DIR, 'direct/showbase'), 
        'direct.interval' : os.path.join(PANDA_DIR, 'direct/interval'), 
        'direct.actor' : os.path.join(PANDA_DIR, 'direct/actor'), 
        'direct.gui' : os.path.join(PANDA_DIR, 'direct/gui'), 
        'direct.task' : os.path.join(PANDA_DIR, 'direct/task'), 
        'direct.control' : os.path.join(PANDA_DIR, 'direct/control'), 
        'direct.directnotify' : os.path.join(PANDA_DIR, 'direct/directnotify'), 
        'direct.directtools' : os.path.join(PANDA_DIR, 'direct/directtools'), 
        'direct.directutil' : os.path.join(PANDA_DIR, 'direct/directutil'), 
        'direct.fsm' : os.path.join(PANDA_DIR, 'direct/fsm'), 
        'direct.cluster' : os.path.join(PANDA_DIR, 'direct/cluster'), 
        'direct.particles' : os.path.join(PANDA_DIR, 'direct/particles'), 
        'direct.tkpanels' : os.path.join(PANDA_DIR, 'direct/tkpanels'),
        'direct.tkwidgets' : os.path.join(PANDA_DIR, 'direct/tkwidgets'),
        'direct.directdevices' : os.path.join(PANDA_DIR, 'direct/directdevices'), 
        'direct.distributed' : os.path.join(PANDA_DIR, 'direct/distributed'),
        'pandac' : os.path.join(PANDA_DIR, 'pandac'),
        },
    data_files = [
        # a list of data files
        ('etc', [os.path.join(PANDA_DIR, 'etc/Config.prc')]),
        ('avatars', glob.glob('avatars/*.ini') + glob.glob('avatars/*.egg')),
        ('cameras', ['cameras/*.ini']),
        ('config', ['config/init.ini', 'config/mapping.ini', 'config/online.ini', 'config/scene.ini'] + glob.glob('config/*.ini')),
        
        # make sure all dlls are copied from Panda3D
        ('.', glob.glob(os.path.join(PANDA_DIR, 'bin/*.dll'))),
        ],
)

How big is the compiled .exe file? Using PandaPack on a small thing I made the install file is 17MB and when installed 80MB. Does py2exe beat that? (cant imagine it not beating it :slight_smile:)

depends on the data of your project.

but py2exe does not create one executable but an executable, one zip (with all Python/Panda3D code), many dlls, and your data directories. so it’s not a one-exe solution, but creates a distribution directory, which you can compress and provide to uncompress and run (without the need to install Panda3D or Python on the host computer).

or i didn’t figure out how to create one-exe. :wink:

cheers,
kaweh

Using py2exe you can get rid of the zip-file containing all the python bytecode by setting the zipfile-option to None. Then py2exe appends the zipfile to the .exe file, which gets bigger of course. I have used this trick with other python project (wxPython), and so far didn’t encounter any problems.

setup( windows = [ { 'script' : 'foo.py',
                     'icon_resources' : [ ( 1, 'foo.ico' ) ],
                     } ],
       #zipfile = 'library.zip',
       zipfile = None,
       options = { 'py2exe': { 'optimize' : 2,
...

A way to get a “fake” single-file-executable is described here:

http://www.py2exe.org/index.cgi/SingleFileExecutable

Using NSIS you can pack the .exe, all the dll’s and data files into one .exe-file, which unpacks on execution into a temporary directory. After your application exits the temporary folder is deleted automatically. The drawback is additional time to unpack everything each time you run the application. An advantage might be that the NSIS zip algorithm (based on 7zip) packs much better than the one used by py2exe, and total size might be reduced to one third.

Finally, if size is a matter then having a look at UPX might be interesting. UPX can reduce the size off executable (.exe, .dll, …) files to about 30%-60% of their original size. I used UPX with great success to make wxPython and other .dll’s smaller, but I didn’t try with Panda3d so far.

http://upx.sourceforge.net/

I hope these general tips help. I didn’t try any of them with Panda3d so far.
enn0x

Thanks a million for the tips! I’ll give them a try!

cheers,
kaweh

So has any of you guys tried packpanda that comes with panda? If yes, how would you say that compares to py2exe? Is the gain significant (I am especially interested in space-gain since pandapack creates pretty big files)?. Why would you choose py2exe over pandapack - it seems more tedious to use (I just downloaded it - think it will take most of saturday to make it work…).

Hello

I am sure there are reasons to keep application size low, but I think in most cases the 3d content (models, textures, word configuration) will be the main bulk of a Panda3d application.

Anyway, if you want to distribute your code there are two things you might want to do:
1.) Provide an easy way to install your software. Usually a one-file installer.
2.) Hide your code and 3d content from prying eyes.

About Packpanda:

I have used packpanda only once, doing a test with a minimal Panda3d application. Packpanda is basically a frontend to NSIS, so it generates a one-file installer. It does so by packing everything into a large archive. Everything means it packs the complete python distribution that comes with Panda3d, even the compiled help file (another 4mb).

Advantages:
-Very easy to use :slight_smile:

Disadvantages:

  • Even without 3d content your application will be around 70mb. There may be ways to teak with packpanda, but I don’t know them.
  • It doesn’t hide your code well. There is an option (–pyc --rmext py) to exclude .py files, but python bytecode can be hacked rather easy and the files are visible on your hard drive.

About py2exe:

Py2exe uses python distutils to collect everyrthing that is needed for your application (every module you import, be it .py or .dll), copies everything into a single directory, and creates an .exe to start your application. It does not create an installer.

Advantages:

  • Smaller application. I managed to create an test application using py2exe with only 32mb (without 3d content). Compressing everything except avcodec-51-panda.dll using upx I got size down to 13mb.
  • Hides your code a little bit better, but still just an annoyance for hackers. The .pyc files are inside a zip file, and easy to extract.

Disadvantages:

  • No installer. Of course you can pack your distribution using one of the many free installers (e.g. Microsoft Wix/MSI, NSIS, Inno Setup), but you have to spend time on finding out how to configure the installers.
  • Py2exe doesn’t work well with Panda3d, at least not yet. Thanks a lot kaweh for providing the tips above.