4

I've got a small application I've built as a utility for the other members of my office. I'm an I.T. guy in a decidedly non-technological industry, so I'm trying to make this as simple as possible while still giving myself the ability to change the program without re-freezing it in its entirety. My program, therefore, looks like this:

| C:\Program Files (x86)\company_name\product_name
| | findppw.exe (my script)
| | runtime files that are built during the freeze
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
| %APPDATA%\company_name\product_name\
| | Reports\
| | | This gets filled with temp files only
| | Logs\
| | | This gets filled with log files
| | config.ini
| | stores.ini

I'm having some trouble with preparing the %APPDATA% folder, which should be the focus of this question.

My findppw.pyw script has the following imports:

from tkinter import *
from tkinter import ttk
import threading
from collections import OrderedDict
import datetime
import zipfile
from tempfile import NamedTemporaryFile
import queue
import os,sys # for sys.exit and os.startfile
import logging
from appdirs import AppDirs # to find %appdata% equivalent
import ast # for literal_eval of info in stores.ini and config.ini

I've tried using both cx_Freeze and py2exe for the freezing of it.

py2exe:

py2exe will compile the program correctly with or without a setup script, but in both cases the resulting executable throws a Windows error when launched: "Find Paperwork has stopped working" with no further information. The log files created by the dump are of no use to me in troubleshooting, though I can provide them upon request if someone think they'll be useful.

cx_Freeze:

When py2exe failed me, I went looking for an alternative and found cx_Freeze. It promised the ability to use an installer ("hooray," I think, "that should handle the %APPDATA% setup for me!") but I'm a little lost on how to set up the setup.py to handle it in this way, indeed if it's even possible! My alternative is to make an initialize function in my script that checks for the existence of these folders/files and creates them to some initial hard-coded value if they do not exist. That just FEELS like the work of an installer, though, not the executable.

As an upshot, though, the executable functions so there's that....

The Question:

How can I write a setup.py script for cx_Freeze EDIT: an excellent comment recommended use of pyinstaller as well, so let me amend this to say ANY library that throws data files in the right place, while leaving me with a windows installer I can use to distribute the program to other intraoffice systems?

Corollary, but likely outside of the scope of this question: why did the py2exe method fail?

Community
  • 1
  • 1
Adam Smith
  • 52,157
  • 12
  • 73
  • 112
  • 1
    I've generally had luck with [pyinstaller](http://www.pyinstaller.org/) more than with the other libraries you linked. So while I'm not sure it handles your problem, it is generally simpler to use. – user3820547 Jul 10 '14 at 17:28
  • @user3820547 I'm not against using a DIFFERENT library to accomplish the same goal, but `pyinstaller` specifically says in its FAQ: "Building an installer program is totally outside the scope of PyInstaller." This isn't a deal breaker to me, but I still need to get those files to create correctly, which means an init script I'm trying to avoid if possible – Adam Smith Jul 10 '14 at 19:39
  • @AdamSmith Maybe you can use pyinstaller to create the binary, and use something like [Wix](http://wixtoolset.org/) to create the installer itself. – parchment Jul 16 '14 at 16:01
  • 1
    If you're planning to make an installer anyway, have a look at my new project [Pynsist](http://pynsist.readthedocs.org/en/latest/). It doesn't try to freeze your program to an exe, but it installs it along with the necessary version of Python, and sets up start menu shortcuts for it. I think that's easier to customise than freeze tools (though I'm biased, of course). – Thomas K Jul 16 '14 at 16:59
  • @ThomasK I'm installing in a corporate environment. Although I'd prefer every environment I need to support has Python installed, it'll be a whole different can of worms to get our Security Officer to sign off on that rather than just inspect my source and OK the binary. – Adam Smith Jul 16 '14 at 17:12
  • Technically, it's not that different - you specify the exact version of Python, and whether it's frozen into an executable or installed in another directory, you're still putting a Python interpreter onto the system. But I appreciate that corporate security people might not be easily persuaded of that. I'm familiar with cx_Freeze: the installers it makes aren't very flexible. If you use that, you can either use a separate tool (InnoSetup and NSIS are the most popular) to build a more versatile installer for your exe, or have the initialisation step in your own code. – Thomas K Jul 16 '14 at 17:28
  • @ThomasK I'll take a deeper look at it. I encourage you to write this up as an answer if you have enough time to make a detailed write up – Adam Smith Jul 16 '14 at 17:45
  • Let me make sure I understand, the over arching goal is that you have a python app that you want to share with the rest of your office, correct? – wnnmaw Jul 17 '14 at 19:05
  • @wnnmaw Exactly so. I'm one of four in the IT dept and wrote a script that will help our accounting dept find missing reports by looking them up automagically from our backup server (previously they'd have to send a request to IT to get them manually). When we were running XP, my script simply saved its required files to its install directory (`C:\program files\company name\script name`) but now in win7 our users don't have write permission to `C:\program files (x86)` so I'm trying to move its files to `%APPDATA%`. This created issues in freezing the script into a binary. – Adam Smith Jul 17 '14 at 19:08
  • Is there any shared server that everyone has access to? – wnnmaw Jul 17 '14 at 19:10
  • @wnnmaw Only one cross-department, and access is segmented to various user folders so I have access to `\\192.168.1.23\adsmith` but not `\\192.168.1.23\jdoe`. Access is not locked down anywhere (which is why I'm able to find those reports on the backup server) but drives are not mapped and staff don't generally know how to use the network in that way. – Adam Smith Jul 17 '14 at 19:13
  • 1
    @AdamSmith, well there goes my idea of installing python on the shared drive and running it as a raw python file – wnnmaw Jul 17 '14 at 19:16
  • Do you want files copied to the AppData folder during installation, or do you just want the directory made? – oyvind Jul 18 '14 at 21:44
  • @oyvind At install time two files should be copied to `%AppData%\company_name\product_name`, and two empty directories should be put there as well. I'll be honest, though, only the empty directories would NEED to be there -- the two `ini` files could just as easily go into the directory with the program. – Adam Smith Jul 18 '14 at 21:47
  • Please post your code that you are using to copy to %AppData%, I believe that is where your application is failing. I don't think that the issue is what you use to bundle, but I prefer PyInstaller because it is easy to use, easy to bundle files with it but those files will need to be moved to your AppData directory after the app is run, as it extracts and executes from TEMP. –  Jul 19 '14 at 10:44

2 Answers2

1

I would disagree that this is a job for the installer. If you incorporate a check (How to check if a directory exists and create it if necessary?) every time you start the program, your program won't be bricked if the appdata folder disappears.

If you need to write to the ini files after installation, they should be in the appdata folder. In that case, the copies in the program folder serve as templates, and can be copied as needed.

Regarding cx_freeze: Use command python setup.py bdist_msi to make msi. There are samples for setup files in https://bitbucket.org/anthony_tuininga/cx_freeze/src/bd72fda4b395257c3d8e170213c039f2da40dd2f/cx_Freeze/samples/?at=default, and also in the cx_freeze installation. Documentation is at http://cx-freeze.readthedocs.org/en/latest/index.html.

Community
  • 1
  • 1
oyvind
  • 1,429
  • 3
  • 14
  • 24
0

I'm not sure if I understand your question but you can py2exe or pyinstaller to create the binary. Then find any missing libraries manually and create an installer using Inno Setup. Maybe a log would help.